C++ 核心知识点精讲
覆盖:类和对象 · 继承和多态 · 运算符重载 · 模板 —— 含6道经典例题与详细解析
类和对象
核心语法关键语法说明
- 类定义:
class ClassName { };以分号结尾。成员默认私有(private),可用public、protected指定访问权限。 - 构造函数:与类同名,无返回类型,可重载。对象创建时自动调用。注意初始化列表
: 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 前构造。main 中 t(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。 - 重载规则:不能创建新运算符,不能改变优先级和结合性;
::..*?:等不能重载。=[]()->只能重载为成员函数。 - 自增/自减:前置
++obj为T& operator++(),后置obj++为T operator++(int)(int 为标记,仅用于区分)。 - 输入输出运算符:
>>和<<通常重载为非成员函数(友元),如istream& operator>>(istream& in, MyClass& obj);
例题3:复数类加法重载
请实现一个 Complex 类,包含实部 real 和虚部 imag(double),重载 +、- 运算符(成员函数或友元),并重载 << 输出运算符以 (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,返回两个同类型中的较大者。并测试 int、double、string 类型。
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> 存储,提供 push、pop、top 和 empty 方法,并写一个 main 测试 int 和 string 栈。
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;
}
💡 建议动手把代码敲一遍,并尝试修改参数、增加继承层次或重载运算符,加深理解。
⚠️ 考试时特别注意虚函数表在构造/析构阶段的行为、模板编译期的特性,以及运算符重载返回引用的时机。
🎯 祝考试顺利!