c++++中多态的核心在于通过虚函数实现“一个接口,多种方法”。1. 使用virtual关键字在基类中声明虚函数;2. 派生类重写虚函数并使用override提高可读性;3. 通过基类指针或引用调用虚函数,实际执行派生类的实现。若不使用虚函数,则调用始终绑定到基类函数。虚函数表(vtable)在编译时生成,存储虚函数地址,对象通过虚函数指针(vptr)访问对应vtable以实现运行时动态绑定。纯虚函数使类成为抽象类,必须被继承并重写才能实例化派生类。多重继承下,派生类可能拥有多个vptr以支持不同基类的虚函数调用。

C++中多态的核心在于允许你使用指向基类的指针或引用来调用派生类中的函数,从而实现“一个接口,多种方法”。 这背后的机制涉及虚函数表(vtable)和虚函数指针(vptr),使得在运行时能够确定实际调用的函数。

解决方案
多态的实现主要依赖于虚函数。 当一个类中声明了虚函数,编译器会为该类创建一个虚函数表(vtable),其中存储了该类及其父类的虚函数地址。 类的每个对象都会包含一个指向该vtable的虚函数指针(vptr)。

-
虚函数声明: 在基类中使用
virtual
关键字声明虚函数。立即学习“C++免费学习笔记(深入)”;
class Base { public: virtual void display() { std::cout << "Base class display" << std::endl; } }; -
派生类重写: 在派生类中重写(override)基类的虚函数。 注意override关键字可以提高代码可读性,避免错误。

class Derived : public Base { public: void display() override { std::cout << "Derived class display" << std::endl; } }; -
通过指针或引用调用: 通过基类指针或引用调用虚函数。
Base* basePtr; Derived derivedObj; basePtr = &derivedObj; basePtr->display(); // 输出 "Derived class display"
在这个例子中,
basePtr指向的是
Derived类的对象,尽管
basePtr是
Base类型的指针,但由于
display函数是虚函数,所以实际调用的是
Derived类中的
display函数。 这就是多态的体现。
那么,没有虚函数会怎样? 如果
display函数不是虚函数,那么
basePtr->display()将始终调用
Base类中的
display函数,即使
basePtr指向的是
Derived类的对象。
本书是全面讲述PHP与MySQL的经典之作,书中不但全面介绍了两种技术的核心特性,还讲解了如何高效地结合这两种技术构建健壮的数据驱动的应用程序。本书涵盖了两种技术新版本中出现的最新特性,书中大量实际的示例和深入的分析均来自于作者在这方面多年的专业经验,可用于解决开发者在实际中所面临的各种挑战。
什么是虚函数表(vtable)?
虚函数表(vtable)是一个存储类虚函数地址的查找表。 每个包含虚函数的类都有一个 vtable。 vtable 是编译器在编译时生成的,通常是静态的。 类的每个对象(包含虚函数)都会有一个指向其 vtable 的指针(vptr)。 这个指针通常位于对象的内存布局的起始位置。
vtable 使得在运行时能够动态地确定应该调用哪个函数。 当通过基类指针或引用调用虚函数时,程序会通过 vptr 找到 vtable,然后在 vtable 中查找正确的函数地址并调用它。
纯虚函数与抽象类
纯虚函数是在基类中声明但没有定义的虚函数。 包含纯虚函数的类被称为抽象类。 抽象类不能被实例化,只能被继承。 派生类必须重写基类中的所有纯虚函数才能被实例化。
class Shape {
public:
virtual double area() = 0; // 纯虚函数
};
class Circle : public Shape {
public:
Circle(double r) : radius(r) {}
double area() override { return 3.14159 * radius * radius; }
private:
double radius;
};在这个例子中,
Shape是一个抽象类,因为它包含一个纯虚函数
area()。
Circle类继承了
Shape类并重写了
area()函数,因此
Circle类可以被实例化。 如果
Circle类没有重写
area()函数,那么
Circle类也将是一个抽象类。
多重继承与多态
多重继承是指一个类继承自多个基类。 在多重继承的情况下,派生类可能会有多个 vptr,每个 vptr 指向一个基类的 vtable。 这会增加多态实现的复杂性,需要仔细设计类的继承关系和虚函数。
例如:
class Base1 {
public:
virtual void display() { std::cout << "Base1" << std::endl; }
};
class Base2 {
public:
virtual void show() { std::cout << "Base2" << std::endl; }
};
class Derived : public Base1, public Base2 {
public:
void display() override { std::cout << "Derived (Base1)" << std::endl; }
void show() override { std::cout << "Derived (Base2)" << std::endl; }
};
int main() {
Derived d;
Base1* b1 = &d;
Base2* b2 = &d;
b1->display(); // 输出 "Derived (Base1)"
b2->show(); // 输出 "Derived (Base2)"
return 0;
}在这个例子中,
Derived类继承自
Base1和
Base2。
Derived类重写了
Base1的
display函数和
Base2的
show函数。 通过
Base1和
Base2的指针调用虚函数时,会分别调用
Derived类中对应的函数。 注意,这里
Derived类对象实际上有两个 vptr,分别对应
Base1和
Base2。








