C++ 核心知识点精讲

覆盖:类和对象 · 继承和多态 · 运算符重载 · 模板 —— 含6道经典例题与详细解析

类和对象

核心语法

关键语法说明

  • 类定义:class ClassName { }; 以分号结尾。成员默认私有(private),可用 publicprotected 指定访问权限。
  • 构造函数:与类同名,无返回类型,可重载。对象创建时自动调用。注意初始化列表 : member(value) {} 的用法。
  • 析构函数:~ClassName(),无参无返回,负责资源释放。对象销毁时自动调用。
  • 拷贝构造函数:ClassName(const ClassName& other),用已有对象初始化新对象时调用。深拷贝与浅拷贝的区别要清楚。
  • this 指针:指向对象自身的指针,在成员函数中隐式可用,常用于返回对象自身。
  • 常成员函数:返回类型 函数名(参数) const; 表示不会修改对象成员,const 对象只能调用 const 成员函数。
  • 静态成员:static 成员变量属于类本身,所有对象共享,类外需定义;静态成员函数只能访问静态成员。

例题1:构造函数与析构顺序

example1.cpp
#include <iostream>
                            using namespace std;

                            class Test {
                            public:
                            Test(int n) : id(n) { cout << "构造 " << id << " "; }
                            ~Test() { cout << "析构 " << id << " "; }
                            private:
                            int id;
                        };

                        Test global(1);          // 全局对象

                        void func() {
                            Test local(2);       // 局部对象
                            static Test st(3);   // 局部静态对象(只构造一次)
                        }

                        int main() {
                            Test t(4);
                            func();
                            func();
                            return 0;
                        }
📝 解析:全局对象 global(1)main 前构造。maint(4) 构造。第一次调用 func():构造 local(2),静态局部 st(3) 只在第一次进入时构造一次;函数结束时 local(2) 销毁。第二次 func():再次构造 local(2),静态对象不再构造;函数结束销毁 local(2)main 结束后销毁 t(4),然后全局和静态对象按构造相反顺序销毁:st(3)global(1)

输出结果:

构造 1 构造 4 构造 2 构造 3 析构 2 构造 2 析构 2 析构 4 析构 3 析构 1

继承和多态

核心语法

关键语法说明

  • 继承方式:class Derived : public Base(公有继承),protected/private 继承会改变基类成员在派生类中的访问级别。通常考试用 public 继承。
  • 构造函数与析构顺序:构造时先基类后派生类,析构时先派生类后基类
  • 多态条件:① 基类函数声明为 virtual;② 通过基类指针或引用调用虚函数;③ 派生类重写(覆盖)该虚函数(函数签名相同)。
  • 虚函数:virtual 返回类型 函数名(); 可以在基类中给出默认实现。派生类覆盖时可加 override 关键字(C++11)提示编译器检查。
  • 纯虚函数与抽象类:virtual void func() = 0; 至少有一个纯虚函数的类为抽象类,不能实例化。派生类必须实现所有纯虚函数才能成为具体类。
  • 虚析构函数:如果类作为基类使用,通常应将析构函数声明为虚,确保派生类对象通过基类指针删除时正确调用派生类析构函数。

例题2:虚函数与构造析构顺序

example2.cpp
#include <iostream>
                            using namespace std;

                            class Base {
                            public:
                            Base() { cout << "B "; show(); }
                            virtual ~Base() { cout << "~B "; }
                            virtual void show() { cout << "Base::show "; }
                        };

                        class Derived : public Base {
                        public:
                        Derived() { cout << "D "; }
                        ~Derived() { cout << "~D "; }
                        void show() override { cout << "Derived::show "; }
                    };

                    int main() {
                        Base* p = new Derived();
                        p->show();
                        delete p;
                        return 0;
                    }
📝 解析:new Derived() 先调 Base 构造函数:输出 B ,构造函数中调用 show(),此时对象的虚表还是 Base 的虚表(派生类还没构造完),所以调用 Base::show,输出 Base::show ;然后 Derived 构造函数输出 D
p->show() 通过基类指针调虚函数,动态绑定到 Derived::show,输出 Derived::show
delete p:因析构函数是虚的,先调 ~Derived() 输出 ~D ,再调 ~Base() 输出 ~B

输出结果:

B Base::show D Derived::show ~D ~B

运算符重载

核心语法

关键语法说明

  • 成员函数重载:返回类型 operator运算符(参数表) { }。左操作数是对象自身(this)。如 Complex operator+(const Complex& other) const; 表示 c1 + c2
  • 友元函数重载:friend 返回类型 operator运算符(参数1, 参数2); 常用于左操作数不是本类对象的场景,或需要访问私有成员。如 friend Complex operator+(double d, const Complex& c); 支持 3.5 + c1
  • 重载规则:不能创建新运算符,不能改变优先级和结合性;:: . .* ?: 等不能重载。= [] () -> 只能重载为成员函数。
  • 自增/自减:前置 ++objT& operator++(),后置 obj++T operator++(int)(int 为标记,仅用于区分)。
  • 输入输出运算符:>><< 通常重载为非成员函数(友元),如 istream& operator>>(istream& in, MyClass& obj);

例题3:复数类加法重载

请实现一个 Complex 类,包含实部 real 和虚部 imagdouble),重载 +- 运算符(成员函数或友元),并重载 << 输出运算符以 (a, b) 形式打印。

complex.cpp
#include <iostream>
                            using namespace std;

                            class Complex {
                            private:
                            double real, imag;
                            public:
                            Complex(double r = 0, double i = 0) : real(r), imag(i) {}

                            // 成员函数重载 +
                            Complex operator+(const Complex& other) const {
                                return Complex(real + other.real, imag + other.imag);
                            }

                            // 成员函数重载 -  (this - other)
                            Complex operator-(const Complex& other) const {
                                return Complex(real - other.real, imag - other.imag);
                            }

                            // 友元重载 <<
                            friend ostream& operator<<(ostream& os, const Complex& c) {
                                os << "(" << c.real << ", " << c.imag << ")";
                                return os;
                            }
                        };

                        int main() {
                            Complex a(3, 4), b(1, 2);
                            cout << a + b << endl;   // (4, 6)
                            cout << a - b << endl;   // (2, 2)
                            return 0;
                        }

例题4:自增运算符重载

写出 Counter 类,包含 int count;,重载前置 ++ 和后置 ++,并测试。

counter.cpp
class Counter {
                            int count;
                            public:
                            Counter(int c = 0) : count(c) {}
                            // 前置++
                            Counter& operator++() {
                                ++count;
                                return *this;
                            }
                            // 后置++ (int 仅用于区分)
                            Counter operator++(int) {
                                Counter temp = *this;
                                ++count;   // 或 count++;
                                return temp;
                            }
                            int getCount() const { return count; }
                        };
⚠️ 注意:后置 ++ 返回的是旧值,并且返回的是对象本身而不是引用(因为局部变量 temp 在函数结束时销毁,不能返回引用)。前置 ++ 返回引用 Counter&,支持链式调用如 ++(++c)

模板

核心语法

关键语法说明

  • 函数模板:template <typename T>template <class T>,使函数能适应多种类型。如:template <typename T> T max(T a, T b) { return a > b ? a : b; }
  • 类模板:template <typename T> class ClassName { ... };,成员函数在类外定义时需要加上模板声明和 <T>。如:template<typename T> void Stack<T>::push(const T& val) {...}
  • 模板特化:可对特定类型提供特殊实现,如全特化 template<> class Stack<bool> { ... };
  • 默认模板参数:template<typename T = int> class Array { ... };
  • 非类型模板参数:template<typename T, int SIZE> class Buffer { T data[SIZE]; };SIZE编译期常量

例题5:函数模板比较大小

实现函数模板 myMax,返回两个同类型中的较大者。并测试 intdoublestring 类型。

mymax.cpp
#include <iostream>
                            #include <string>
                            using namespace std;

                            template <typename T>
                            T myMax(T a, T b) {
                                return (a > b) ? a : b;
                            }

                            int main() {
                                cout << myMax(3, 7) << endl;           // 7
                                cout << myMax(2.5, 1.8) << endl;        // 2.5
                                string s1 = "apple", s2 = "banana";
                                cout << myMax(s1, s2) << endl;          // banana (字典序)
                                return 0;
                            }

例题6:简单栈类模板

定义一个类模板 Stack<T>,内部用 vector<T> 存储,提供 pushpoptopempty 方法,并写一个 main 测试 intstring 栈。

stack_template.cpp
#include <iostream>
                                #include <vector>
                                #include <string>
                                #include <stdexcept>
                                using namespace std;

                                template <typename T>
                                class Stack {
                                vector<T> elems;
                                public:
                                void push(const T& val) { elems.push_back(val); }
                                void pop() {
                                    if (elems.empty()) throw out_of_range("Stack empty");
                                    elems.pop_back();
                                }
                                T top() const {
                                    if (elems.empty()) throw out_of_range("Stack empty");
                                    return elems.back();
                                }
                                bool empty() const { return elems.empty(); }
                            };

                            int main() {
                                Stack<int> intStack;
                                intStack.push(10);
                                intStack.push(20);
                                cout << intStack.top() << endl;  // 20
                                intStack.pop();
                                cout << intStack.top() << endl;  // 10

                                Stack<string> strStack;
                                strStack.push("hello");
                                strStack.push("world");
                                cout << strStack.top() << endl;  // world
                                return 0;
                            }

💡 建议动手把代码敲一遍,并尝试修改参数、增加继承层次或重载运算符,加深理解。

⚠️ 考试时特别注意虚函数表在构造/析构阶段的行为模板编译期的特性,以及运算符重载返回引用的时机

🎯 祝考试顺利!