C++多态与虚函数
一、虚函数基础
1. 概念定义
- 虚函数:用
virtual
关键字声明的成员函数 - 核心作用:实现运行时多态,允许派生类重写基类方法
- 调用特性:通过基类指针/引用调用时,根据实际对象类型决定调用版本
2. 定义格式
cpp
class Base {
public:
virtual ReturnType funcName(ParameterList);
// 虚函数声明
};
3. 函数重写要求
- 三同原则:
- 函数名相同
- 参数列表相同
- 返回类型相同(C++11允许协变返回类型)
二、多态实现三要素
- 继承关系:存在继承体系的类层次结构
- 虚函数重写:派生类重写基类虚函数
- 基类指针/引用:使用基类类型的指针或引用操作派生类对象
三、纯虚函数与抽象类
1. 定义格式
cpp
virtual ReturnType funcName() = 0;
2. 核心特性
- 使类成为抽象类(不可实例化)
- 强制派生类必须实现该接口
- 典型应用场景:
- 定义接口规范
- 创建通用基类模板
四、虚函数表机制
1. 实现原理
- vtable:编译器为含虚函数的类生成的函数指针数组
- vptr:每个对象隐含的指向vtable的指针(通常位于对象起始位置)
2. 继承体系中的表现
继承类型 | vtable特性 |
---|---|
单继承 | 派生类vtable包含基类vtable内容,重写函数覆盖基类条目 |
多继承 | 派生类维护多个vtable(对应每个基类),重写函数更新所有相关条目 |
五、特殊函数处理
1. 虚析构函数
cpp
class Base {
public:
virtual ~Base() {} // 虚析构函数声明
};
- 必要性:确保通过基类指针删除派生类对象时正确调用完整析构链
- 内存安全:防止派生类资源泄漏
2. 限制说明
构造函数
:
-
不能为虚函数(对象构造时vptr尚未初始化)
-
不能声明为
virtual
友元函数
:
- 不属于类成员,不能声明为虚函数
六、现代C++特性
1. override关键字
cpp
class Derived : public Base {
void func() override; // 显式声明重写
};
- 作用:显式标记函数重写,增强代码可读性
- 优势:编译器检查重写有效性,避免签名错误
2. final关键字
cpp
class Base {
virtual void func() final; // 禁止派生类重写
};
class Derived final {}; // 禁止继续继承
- 类级使用:禁止类被继承
- 函数级使用:禁止虚函数被重写
七、关键注意事项
-
运行时成本:虚函数调用比普通函数多一次间接寻址(查vtable)
-
对象大小:每个含虚函数的对象增加一个指针大小(vptr)
构造/析构顺序
:
- 构造函数中虚函数机制未完全建立
- 析构函数中虚函数机制已部分销毁
-
接口设计:优先使用纯虚函数定义抽象接口
-
继承深度:建议不超过3层,避免过度复杂的继承体系
八、典型代码示例
cpp
// 抽象基类
class Shape {
public:
virtual double area() const = 0; // 纯虚函数
virtual ~Shape() = default; // 虚析构函数
};
class Circle : public Shape {
double radius;
public:
Circle(double r) : radius(r) {}
double area() const override { // 实现纯虚函数
return 3.14159 * radius * radius;
}
};
// 使用示例
void printArea(const Shape& shape) {
cout << "Area: " << shape.area(); // 多态调用
}
int main() {
Circle c(5.0);
printArea(c); // 输出正确的圆面积
return 0;
}