C++中的virtual函数
在 C++ 中,关键字 virtual 用于修饰成员函数,使其成为虚函数,从而支持多态特性。多态是面向对象编程的核心特性之一,允许基类的指针或引用在运行时调用派生类中重写的函数。
1. 基本功能
当一个成员函数被声明为 virtual 时:
- 即使通过基类的指针或引用调用该函数,实际调用的函数是派生类中重写的版本(如果派生类重写了该函数)。
- 这是通过动态绑定(运行时多态)实现的,而非静态绑定(编译时绑定)。
2. 使用示例
代码示例:
#include <iostream>
using namespace std;
class Base {
public:
virtual void show() { // 基类中的虚函数
cout << "Base::show()" << endl;
}
virtual ~Base() {} // 虚析构函数,避免内存泄漏
};
class Derived : public Base {
public:
void show() override { // 重写基类的虚函数
cout << "Derived::show()" << endl;
}
};
int main() {
Base* basePtr = new Derived(); // 基类指针指向派生类对象
basePtr->show(); // 动态绑定,调用派生类的 show()
delete basePtr; // 调用正确的析构函数
return 0;
}
输出:
Derived::show()
3. 关键特性
-
动态绑定
- 当一个函数被声明为
virtual,它会在运行时根据实际对象的类型选择合适的函数。 - 如果没有
virtual,即使基类指针指向派生类对象,也会调用基类的函数(静态绑定)。
示例(未使用
virtual):class Base { public: void show() { // 非虚函数 cout << "Base::show()" << endl; } }; class Derived : public Base { public: void show() { cout << "Derived::show()" << endl; } }; int main() { Base* basePtr = new Derived(); basePtr->show(); // 静态绑定,调用 Base::show() delete basePtr; return 0; }输出:
Base::show() - 当一个函数被声明为
-
override关键字- C++11 引入了
override,用于明确指定派生类重写基类的虚函数。 - 如果派生类的函数签名与基类不匹配(例如参数或返回类型不同),编译器会报错。
- C++11 引入了
-
虚析构函数
- 如果基类的析构函数不是虚函数,可能导致派生类的析构函数不被调用,导致内存泄漏。
- 推荐:基类中的析构函数应始终声明为虚函数。
示例:
class Base { public: virtual ~Base() { cout << "Base destructor" << endl; } }; class Derived : public Base { public: ~Derived() { cout << "Derived destructor" << endl; } }; int main() { Base* basePtr = new Derived(); delete basePtr; // 调用 Derived 和 Base 的析构函数 return 0; }输出:
Derived destructor Base destructor -
纯虚函数
- 如果一个虚函数的实现没有意义,可以将其声明为纯虚函数。
- 纯虚函数的语法是:
virtual void func() = 0; - 包含纯虚函数的类称为抽象类,不能实例化,必须由派生类实现纯虚函数后才能实例化。
示例:
class AbstractClass { public: virtual void show() = 0; // 纯虚函数 }; class ConcreteClass : public AbstractClass { public: void show() override { cout << "ConcreteClass::show()" << endl; } }; int main() { ConcreteClass obj; obj.show(); return 0; }
4. 使用 virtual 的好处
- 支持多态性:通过基类指针或引用操作派生类对象,而无需知道派生类的具体类型。
- 代码可扩展性:可以在派生类中定义新的行为,而无需修改基类代码。
- 避免内存泄漏:通过虚析构函数确保正确的资源清理。
5. 注意事项
-
性能影响:
- 虚函数需要通过虚函数表(vtable)实现动态绑定,这会略微增加时间和空间的开销。
- 但这种开销通常可以接受,特别是在需要多态性的情况下。
-
不能在构造函数或析构函数中调用虚函数:
- 在构造函数或析构函数中调用虚函数,只会调用当前类的实现版本,而不会动态绑定到派生类。
6. 总结
virtual的核心作用是实现运行时多态。- 动态绑定使代码更加灵活和可扩展,但应注意虚函数的性能开销和使用限制。
- 始终将基类的析构函数声明为虚函数,避免资源泄漏问题。
本文来自博客园,作者:海_纳百川,转载请注明原文链接:https://www.cnblogs.com/chentiao/p/18697770,如有侵权联系删除

浙公网安备 33010602011771号