C++ 多态

虚函数与多态

  • 常规多态:virtual + 指针/引用
    • 代码中的 test1()test2()
      • 下图中 a,an,ap,b 的类型,指针/引用记录了类型 B
    • test2()指针/引用会为派生类新加一个虚函数表
    • 是否多态看的还是虚函数表是哪一个(而不是只看形式上是不是指针)
      • 基类和派生类都只有一个虚表
      • 不含有成员变量的前提下:sizeof(A) = sizeof(B) = sizeof(void*)
        • 含有一个虚表的指针
1
2
3
4
5
// test2()
B b;
A a = b; // 虚函数表还是 B 的虚函数表
(&a)->a_v(); // 不多态
a.a_v(); // 不多态

  • 派生类如果没有实现基函数的 virtual 函数,则多态时会调用基类的 virtual 函数
  • 如果基类虚函数中调用了常规函数,但是常规函数在派生类中被覆盖
    • 此时派生类调用这个虚函数时,内部调用的是父类的常规函数
    • 代码中的 test3()
  • 析构函数建议定义为多态
  • 虚函数表一个类一个

虚函数表

  • 派生类复制父类的虚函数表,然后修改 override 的,然后在最后加上自己的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class A {
public:
virtual void a_v() { OUTPUT; }
virtual void b_v() { OUTPUT; }
};

class B : public A {
public:
virtual void a_v() override { OUTPUT; }
virtual void c_v() { OUTPUT; }
};

class C : public B {
public:
virtual void d_v() { OUTPUT; }
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
virtual table address: 00007FF7C453BD48
virtual function 0 --> 00007FF7C453141F --> function: A::a_v
virtual function 1 --> 00007FF7C453134D --> function: A::b_v

virtual table address: 00007FF7C453BD88
virtual function 0 --> 00007FF7C4531311 --> function: B::a_v
virtual function 1 --> 00007FF7C453134D --> function: A::b_v
virtual function 2 --> 00007FF7C453107D --> function: B::c_v

virtual table address: 00007FF7C453BDC0
virtual function 0 --> 00007FF7C4531311 --> function: B::a_v
virtual function 1 --> 00007FF7C453134D --> function: A::b_v
virtual function 2 --> 00007FF7C453107D --> function: B::c_v
virtual function 3 --> 00007FF7C4531451 --> function: C::d_v