C++ 中的虚函数
C++ 中的虚函数是基类中的成员函数,该函数在派生类中被重写。这有助于实现运行时多态性,这意味着要执行的函数是在运行时确定的,而不是在编译时,因为调用的函数取决于实际的对象类型,而不是指针或引用类型。
虚函数声明
在基类中使用 virtual 关键字声明虚函数。
语法
以下是虚函数声明的语法:
class BaseClassName { public: virtual void func_name() { // 执行 } };
其中,
- BaseClassName 是用户指定的基类名称。
- func_name 是指定的函数名称。
虚函数的工作原理
在 C++ 中,虚函数允许运行时多态性,这意味着被调用的函数取决于实际的对象类型,而不是指针或引用类型,这是通过使用称为 vtable(虚表)和 vptr(虚表指针)的机制来实现的。
虚表 (VTable) 和虚拟指针 (VPTR)
虚拟表是为每个包含虚函数的类创建的函数指针表,它存储该类的虚函数地址。
然而,该类中每个具有虚函数的对象都包含一个隐藏的 vptr,该 vptr 指向其类的虚函数表 (vtable)。
分步操作
- 当我们在基类中将函数声明为虚函数时,它将启用动态绑定而不是静态绑定。
- 对于具有虚函数的类,编译器会创建一个 vtable,其中存储指向这些函数的指针。
- 这里,每个具有虚函数的类的对象都有一个 vptr,它指向该类的 vtable。
- 然后,基类指针使用 vptr 在运行时从 vtable 中获取正确的函数,确保调用派生类的重写函数。
示例
#include<iostream> using namespace std; class shape { public: virtual void draw() { // 虚函数 cout << "Creating a shape!" << endl; } }; class circle: public shape { public: void draw() { // 重写虚函数 cout << "Creating a Circle!" << endl; } }; class square: public shape { public: void draw() { // 重写虚函数 cout << "Creating a Square!" << endl; } }; int main() { shape * shapePtr; // 基类指针 circle c; square s; shapePtr = & c; // 指向 circle 对象 shapePtr -> draw(); // 调用 circle 的 draw() 方法 shapePtr = & s; // 指向 square 对象 shapePtr -> draw(); // 调用 square 的 draw() 方法 return 0; }
输出
Creating a Circle!
Creating a Square!
说明
- 首先,创建一个名为 shape 的基类,并为其设置虚函数 draw(),从而为该类建立虚表机制。
- 现在,circle 类继承自 shape 并重写了 draw() 方法,因此当使用 circle 对象时,会调用其 draw() 函数。
- 与 circle 类似,square 类也会重写 draw() 函数。
- 现在,在 int main() 函数中,shape* shapePtr; 是一个 shape 类型的指针,它将指向 circle 或 square 对象。
- shapePtr = &c; 这个基类指针指向 circle 对象 c,并且 shapePtr->draw(); 调用 circle 的 draw() 函数。
- 类似地,shapePtr = &s;这个基类指针指向正方形对象 s,shapePtr->draw(); 调用正方形的 draw() 函数。
虚函数规则
- 虚函数必须在基类中使用"virtual"关键字声明。如果省略 virtual 关键字,则无法动态覆盖。
- 虚函数必须通过基类指针或引用访问。如果直接使用对象访问,则会进行编译时绑定。
- 对于虚函数,基类还必须具有虚析构函数,以防止内存泄漏。如果析构函数不是虚函数,则只会调用基类的析构函数,从而导致内存泄漏。
- 具有纯虚函数的类将成为抽象类,并且无法实例化。如果派生类未重写纯虚函数,它也会成为抽象类。
class Base { public: virtual void show() = 0; // 纯虚函数 };
- 虚函数可以是public或private,其中public可以通过对象或指针访问,而private不能直接访问,但它仍然可以在派生类中被继承和重写。
- 构造函数、静态函数和友元函数不能是虚函数。