- C++
C++ virtual
- 2025-8-11 13:20:35 @
1 条评论
-
admin SU @ 2025-8-11 14:38:08
C++ 虚函数(virtual)学习笔记教程
一、虚函数的基本概念
虚函数是C++中实现多态性的核心机制,它允许在派生类中重写基类的成员函数,并通过基类指针或引用调用派生类的实现。
- 定义方式:在函数声明前加上
virtual
关键字 - 作用:实现动态绑定(运行时多态),即根据对象的实际类型而非指针/引用的声明类型来调用相应的函数
- 特点:仅需在基类中声明时添加
virtual
,派生类中重写的函数自动成为虚函数(即使不加virtual
)
class Base { public: // 声明虚函数 virtual void show() { cout << "Base class show()" << endl; } };
二、虚函数的使用规则
-
重写规则(函数签名需完全一致):
- 函数名必须相同
- 参数列表必须相同(类型、顺序、数量)
- 返回值类型必须相同(协变返回类型除外,即返回基类/派生类指针/引用时可不同)
-
访问控制:派生类中重写的虚函数可以改变访问权限(如基类中public,派生类中protected),但不影响多态调用
-
示例代码:
class Base { public: virtual void func() { // 基类虚函数 cout << "Base::func()" << endl; } }; class Derived : public Base { public: void func() override { // 派生类重写(建议加override关键字) cout << "Derived::func()" << endl; } }; int main() { Base* ptr = new Derived(); ptr->func(); // 输出"Derived::func()",实现动态绑定 delete ptr; return 0; }
三、纯虚函数与抽象类
3.1 纯虚函数
纯虚函数是没有具体实现的虚函数,用于定义接口规范。
- 声明方式:在函数声明后加上
= 0
- 特点:包含纯虚函数的类无法实例化
- 示例:
class Shape { public: virtual double area() const = 0; // 纯虚函数 };
3.2 抽象类
包含纯虚函数的类称为抽象类,它主要作为基类使用,为派生类提供统一接口。
-
规则:
- 抽象类不能创建对象
- 派生类必须实现所有纯虚函数才能成为非抽象类
- 抽象类可以有非纯虚函数和成员变量
-
示例:
class Shape { // 抽象类 public: virtual double area() const = 0; // 纯虚函数 virtual void print() const { // 普通虚函数 cout << "This is a shape" << endl; } }; class Circle : public Shape { private: double radius; public: Circle(double r) : radius(r) {} double area() const override { // 必须实现纯虚函数 return 3.14 * radius * radius; } };
四、虚析构函数
虚析构函数用于确保当通过基类指针删除派生类对象时,能正确调用派生类的析构函数。
- 必要性:如果析构函数不是虚函数,删除基类指针指向的派生类对象时,可能只调用基类析构函数,导致内存泄漏
- 声明方式:在析构函数前加
virtual
关键字
class Base { public: virtual ~Base() { // 虚析构函数 cout << "Base destructor" << endl; } }; class Derived : public Base { private: int* data; public: Derived() { data = new int; } ~Derived() override { // 派生类析构函数 delete data; cout << "Derived destructor" << endl; } }; int main() { Base* ptr = new Derived(); delete ptr; // 先调用Derived析构函数,再调用Base析构函数 return 0; }
五、虚函数表(vtable)原理
C++通过虚函数表实现动态绑定,每个包含虚函数的类都有一个虚函数表(vtable),存储该类所有虚函数的地址。
-
机制:
- 每个对象包含一个指向虚函数表的指针(vptr)
- 派生类的虚函数表继承自基类,重写的函数会替换表中对应位置的地址
- 调用虚函数时,通过vptr找到vtable,再调用对应函数地址
-
特点:
- 增加了内存开销(每个对象多一个指针,每个类多一个虚函数表)
- 虚函数调用比普通函数调用稍慢(需通过指针间接访问)
六、常见问题与注意事项
- 构造函数不能是虚函数:因为对象在构造时,虚函数表尚未完全建立
- 静态成员函数不能是虚函数:静态函数属于类,不依赖对象实例,无法实现动态绑定
- 内联函数与虚函数:虚函数可以声明为inline,但多态调用时不会内联(编译期无法确定具体调用哪个函数)
override
关键字:建议在重写虚函数时使用,编译器会检查是否正确重写,避免因函数签名不一致导致的错误final
关键字:可用于阻止函数被重写或类被继承class Base { public: virtual void func() final {} // 该函数不能被重写 }; class FinalClass final {}; // 该类不能被继承
七、虚函数的应用场景
- 多态行为:如图形系统中,不同图形(圆、矩形等)有不同的面积计算方式
- 接口设计:通过抽象类定义接口,派生类实现具体功能
- 回调机制:利用虚函数实现回调功能
- 框架设计:在框架中定义虚函数作为扩展点,用户通过重写虚函数扩展框架功能
掌握虚函数是学好C++面向对象编程的关键,它为代码的灵活性和可扩展性提供了强大支持,但也需注意合理使用以避免不必要的性能开销。
- 定义方式:在函数声明前加上
- 1