1 运行时多态
/ 动态多态 / 动态绑定
基于 虚函数
, 让 同一 Base ptr / ref ( 同一接口 )
指向 不同 Derived obj ( 不同 对象 )
, 以 呈现出 不同 形态 ( 行为 )
编译时多态 / 静态多态 / 静态绑定:
基于 `non-vf`, 按 non-vf ptr 去调
`不同 重载版本 or 模板实例化`
`静态多态 (实际上 不算多态) 的 2 种形式:`
`1) 函数重载`
`2) 模板`
比较:
1) compiler `编译时 就要确定` 函数的
`参数类型 (只能确定1个类型)`,
运行时 直接调 函数
2) 用 `virtual 关键字 告诉 compiler`,
`编译时 先别确定 参数类型`,
运行时 再根据 `传入的 实际参数类型` 确定
据
1) 编译时 ptr / ref 形参 type (Base*)
调 所属 class (Base) non-vf
2) 运行时 ptr / ref 形参 所指 实际对象 type
调 vf
形参 pbase 的 `静/动 态类型` 是 `Base / Derived`
1.1 non-vf + 静态绑定
non-virtual ( mem ) func 与 non-mem func 的 区别:
仅是 `第 1 para 是 this 指针`
`compiler 在`
(1) 编译 时, 据 class definition
分配 func ptr
(2) 调 non-vf 时
( 运行时 ), 据 this
指针 编译时 type
, 取 相应 func ptr, 调用之
1.2 vf + 动态绑定
1) 只能 用 Base `ptr/ ref 实现`
2) 不能 用 object 实现
reason: obj 的 type 固定, 无法实现 动态类型
`compiler 在 `
(1) 编译时
1) 对 每个 class, 创建 其 vtbl(s):
据 class definition
分配 vf ptr ( addr )
, 写入 相应 vtbl
中 固定 index 位置
2) 将 vf 调用 pb->vf() 转化
为 ( * (pb->vptr_i)[index] ) (pb)
vf ptr 写入 vtbl 中 哪个 index 位置 ?
答: 普遍实现
1> 继承的 vf 优先
继承的 vf `无论是否被 override`, 按
`Base 中 vf 声明顺序`
只是 vf ptr 指向 Derived / Base 相应 vf
2> 本 class `新增 vf`, 按
`Derived 中 vf 声明顺序`
`index = 0 处 写 type_info`
`从 index = 1 开始, 依次写 相应 vf ptr`
(2) 构造 obj 时
`运行时`
在 obj 内存 起始处 写 vptr ( vptr_i ): 指向 obj 实际 class type 的 vtbl
(3) 调 pb->vf() 时
`运行时`
pb 指向 哪种 type ( Base / Derived ) obj
, 就从该 type vtbl
, 即 pb->vptr_i 所指 vtbl
中 取出 相应 vf_ptr: (pb->vptr_i)[index]
, 并 调用之: ( * (pb->vptr_i)[index] ) (pb) = ( * (this->vptr_i)[index] ) (this)
pb 作 mem func 第1实参 隐含传给 第1形参 this
`多继承 有 多 个 vptr ( vptr_i, i = 1, 2, ...)`
1.3 C++ 调 vf
如何确定 从 哪个 vtbl / index 取 func ptr
?
<< 深度探索C++对象模型 >> Function 章
(1) 从 哪个 vtbl 取 ?
`vf 的 调用` 在 `编译期 被转化为 ( * (p->vptr)[index] )(p)` 的形式
=>
`并不是 写死了 调哪个 vf, 只是告诉 compiler`,
去 p->vptr 所指 vtbl ( 运行时 才知是 哪个 vtbl ) 中 index ( 如 index == 1 ) 位置 取
vf ptr
`编译期 无法确定 从 哪个 vtbl 去 取`,
因为 `Base ptr 可能 指向 Base / Derived obj`;
`运行期` 才能 据 `Base ptr 所指 obj`,
`从 该 obj 中 p->vptr 所指 vtbl 中 去取`
`(2) 从 哪个 index 取 ?`
`compiler 编译时 指定 vf ptr 写入 相应 vtbl 哪个 index,
调用 时 就从该 index 取 `
class Base
{
public:
virtual void func1() {}
virtual void func2() {}
};
class Derived : public Base
{
public:
// override
virtual void func1() {}
virtual void func3() {}
};
int main()
{
Base* pb = new Derived;
pb->func1();
}
// single inheritance:
Base vtbl:
index = 1: &Base::func1
index = 2: &Base::func2
Derived vtbl:
index = 1: &Derived::func1 // inherit + override
index = 2: &Base::func2 // inherit + not override
index = 3: &Derived::func3
1.4 note: 用 Base ptr / ref 实现 动态多态
的 前提
Base 必须 有 相应 vf; 否则, 调的是 Base non-vf, 或 调用失败
=> 无法实现 动态多态
见 3.1
2 实现
角度:vf + Inheritance + vptr + vtbl
vtbl : virtual table
vptr : virtual talbe pointer
vf : virtual function
类 继承 or 声明 了 vf, 就有了自己的 vtbls ( n 继承 有 n个 vtbl )
2.1 单继承


2.2 多继承
vptrn: 指向 `继承的 第 n 个 Base` 的 vtbl
`1 种实现:`
vtbl 中 vf ptr 顺序: 按 vf 声明顺序
`vptr1 与 vptr2-n / vtbl 与 vtbl2-n 的 异同?`
`vptr1 / vptr2-n 指向 vtbl / vtbl2-n`
同:
`override / 未 override` 时,
`vtbl 中 vf ptr 指向 Derived / Base 中 vf`
异:
vtbl1 中 vf ptr 还要指向 Derived 新增 vf
而 vtbl2-n 中 vf pointer 则 不用...

3 class 内存分布
角度:单 / 多 / 菱形 继承
3.1 单继承
eg: `Base + non-vf1 / Derived2nd + vf1 =>
Base ptr 调 Derived2nd 对象的 f1,
调的是 Base 的 non-vf1`

#include<iostream>
class Base
{
public:
char *dataBase;
void f1() {}
virtual void f2() {}
};
class Derived: public Base
{
public:
int dataDerived;
virtual void f1() { } // not override f1 in base
void f2() { } // virtual from Inheritance : override f2 in Base
};
class Derived2nd : public Derived
{
public:
int dataDerived2nd;
void f1() { } // virtual from Inheritance : override f1 in Derived
void f2() { } // virtual from Inheritance : override f2 in Derived and Base
};
int main(void)
{
Base base;
Derived derived;
Derived2nd derived2nd;
Base *pbase = NULL;
Derived *pderived = NULL;
Derived2nd *pderived2nd = NULL;
pbase = &derived;
pbase->f1(); // Base1 f1
pbase->f2(); // Derived f2
pbase = &derived2nd;
pbase->f1(); // Base f1
pbase->f2(); // Derived2nd f2
pderived = &derived2nd;
pderived->f1(); // Derived2nd f1
pderived->f2(); // Derived2nd f2
}
查 类的 内存分布
VS 工程 -> 属性 -> C/C++ -> 命令行 -> 其他选项
-> 填 /d1 reportAllClassLayout -> 应用 -> 确定

编译后, 输出窗口

class Base size(8):
+---
0 | {vfptr}
4 | dataBase
+---
Base::$vftable@:
| &Base_meta
| 0
0 | &Base::f2
class Derived size(12):
+---
| +--- (base class Base)
0 | | {vfptr}
4 | | dataBase
| +---
8 | dataDerived
+---
Derived::$vftable@:
| &Derived_meta
| 0
0 | &Derived::f2
1 | &Derived::f1
class Derived2nd size(16):
+---
| +--- (base class Derived)
| | +--- (base class Base)
0 | | | {vfptr}
4 | | | dataBase
| | +---
8 | | dataDerived
| +---
12 | dataDerived2nd
+---
Derived2nd::$vftable@:
| &Derived2nd_meta
| 0
0 | &Derived2nd::f2
1 | &Derived2nd::f1
3.2 多继承
子类 含多个 基类的 内存结构, 包括多个 vtbl
每个继承 当单继承分析

#include<iostream>
class Base1 {
public:
int dataBase1;
virtual void f1() { }
};
class Base2 {
public:
int dataBase2;
virtual void f2() { }
};
class Derived: public Base1, public Base2 {
public:
int dataDerived;
void f1() {}
void f2() {}
void f3() {}
};
int main(void) {
Derived derived;
Base1 *pbase1 = NULL;
Base2 *pbase2 = NULL;
pbase1 = &derived;
pbase1->f1(); //Derived f1
pbase2 = &derived;
pbase2->f2(); //Derived f2
}
class Base1 size(8):
+---
0 | {vfptr}
4 | dataBase1
+---
Base1::$vftable@:
| &Base1_meta
| 0
0 | &Base1::f1
class Base2 size(8):
+---
0 | {vfptr}
4 | dataBase2
+---
Base2::$vftable@:
| &Base2_meta
| 0
0 | &Base2::f2
class Derived size(20):
+---
| +--- (base class Base1)
0 | | {vfptr}
4 | | dataBase1
| +---
| +--- (base class Base2)
8 | | {vfptr}
12 | | dataBase2
| +---
16 | dataDerived
+---
Derived::$vftable@Base1@:
| &Derived_meta
| 0
0 | &Derived::f1
Derived::$vftable@Base2@:
| -8 //why is -8?
0 | &Derived::f2
3.3 菱形继承
1. 1级继承 not 虚继承

菱形冲突:
(1) 最远子类
从 2个 中间子类
都继承了 共同父类
的 共同 mem data/func
=> 最远子类对象
中 存了2份 Inherited 共同父类 的 mem data / vptr
(2) 用 共同父类 pointer
调 最远子类对象 该 共同 mem data/func
时, compiler 不知道该 调2份中哪1份
=> 编译报错 base class is ambiguous
解决: 中间子类均
虚继承
共同父类,
每个 中间子类
增加1个 vbptr
, 指向 共同虚基类
`vbptr: virtual base table pointer`
#include<iostream>
class Base {
public:
int dateBase;
virtual void f1(){}
};
class Derived1: public Base {
public:
int dataDerived1;
virtual void f2(){}
};
class Derived2: public Base {
public:
int dataDerived2;
virtual void f3(){}
};
class Derived2nd: public Derived2, public Derived1 {
public:
int dateDerived2nd;
void f1() {}
void f2() {}
void f3() {}
};
int main(void) {
Derived2nd derived2nd;
Derived1 *pderived1 = NULL;
pderived1 = &derived2nd;
pderived1->f2();
Base *pbase = NULL;
pbase = &derived2nd; // error: base class is ambiguous
}
class Base size(8):
+---
0 | {vfptr}
4 | dateBase
+---
Base::$vftable@:
| &Base_meta
| 0
0 | &Base::f1
class Derived1 size(12):
+---
| +--- (base class Base)
0 | | {vfptr}
4 | | dateBase
| +---
8 | dataDerived1
+---
Derived1::$vftable@:
| &Derived1_meta
| 0
0 | &Base::f1
1 | &Derived1::f2
class Derived2 size(12):
+---
| +--- (base class Base)
0 | | {vfptr}
4 | | dateBase
| +---
8 | dataDerived2
+---
Derived2::$vftable@:
| &Derived2_meta
| 0
0 | &Base::f1
1 | &Derived2::f3
class Derived2nd size(28):
+---
| +--- (base class Derived2)
| | +--- (base class Base)
0 | | | {vfptr}
4 | | | dateBase
| | +---
8 | | dataDerived2
| +---
| +--- (base class Derived1)
| | +--- (base class Base)
12 | | | {vfptr}
16 | | | dateBase
| | +---
20 | | dataDerived1
| +---
24 | dateDerived2nd
+---
Derived2nd::$vftable@Derived2@:
| &Derived2nd_meta
| 0
0 | &Derived2nd::f1
1 | &Derived2nd::f3
Derived2nd::$vftable@Derived1@:
| -12
0 | &thunk: this-=12; goto Derived2nd::f1
1 | &Derived2nd::f2
2. 虚继承

#include<iostream>
using namespace std;
class Base {
public:
int dateBase;
virtual void f1() {}
};
// virtual Inherit
class Derived1: virtual public Base {
public:
int dataDerived1;
virtual void f2() {}
};
// virtual Inherit
class Derived2: virtual public Base {
public:
int dataDerived2;
virtual void f3(){}
};
class Derived2nd: public Derived2, public Derived1 {
public:
int dateDerived2nd;
void f1() {}
void f2() {}
void f3() {}
};
int main(void)
{
Derived2nd derived2nd;
Derived1 *pderived1 = NULL;
pderived1 = &derived2nd;
pderived1->f2();
Base *pbase = NULL;
pbase = &derived2nd;
pbase->f1();
}
class Base size(8):
+---
0 | {vfptr}
4 | dateBase
+---
Base::$vftable@:
| &Base_meta
| 0
0 | &Base::f1
Base::f1 this adjustor: 0
-----------------------------
class Derived1 size(20):
+---
0 | {vfptr}
4 | {vbptr}
8 | dataDerived1
+---
+--- (virtual base Base)
12 | {vfptr}
16 | dateBase
+---
Derived1::$vftable@Derived1@:
| &Derived1_meta
| 0
0 | &Derived1::f2
Derived1::$vbtable@:
0 | -4
1 | 8 (Derived1d(Derived1+4)Base)
Derived1::$vftable@Base@:
| -12
0 | &Base::f1
Derived1::f2 this adjustor: 0
vbi: class offset o.vbptr o.vbte fVtorDisp
Base 12 4 4 0
-----------------------------
class Derived2 size(20):
+---
0 | {vfptr}
4 | {vbptr}
8 | dataDerived2
+---
+--- (virtual base Base)
12 | {vfptr}
16 | dateBase
+---
Derived2::$vftable@Derived2@:
| &Derived2_meta
| 0
0 | &Derived2::f3
Derived2::$vbtable@:
0 | -4
1 | 8 (Derived2d(Derived2+4)Base)
Derived2::$vftable@Base@:
| -12
0 | &Base::f1
Derived2::f3 this adjustor: 0
vbi: class offset o.vbptr o.vbte fVtorDisp
Base 12 4 4 0
-----------------------------
class Derived2nd size(36):
+---
| +--- (base class Derived2)
0 | | {vfptr}
4 | | {vbptr}
8 | | dataDerived2
| +---
| +--- (base class Derived1)
12 | | {vfptr}
16 | | {vbptr}
20 | | dataDerived1
| +---
24 | dateDerived2nd
+---
+--- (virtual base Base)
28 | {vfptr}
32 | dateBase
+---
Derived2nd::$vftable@Derived2@:
| &Derived2nd_meta
| 0
0 | &Derived2nd::f3
Derived2nd::$vftable@Derived1@:
| -12
0 | &Derived2nd::f2
Derived2nd::$vbtable@Derived2@:
0 | -4
1 | 24 (Derived2ndd(Derived2+4)Base)
Derived2nd::$vbtable@Derived1@:
0 | -4
1 | 12 (Derived2ndd(Derived1+4)Base)
Derived2nd::$vftable@Base@:
| -28
0 | &Derived2nd::f1
Derived2nd::f1 this adjustor: 28
Derived2nd::f2 this adjustor: 12
Derived2nd::f3 this adjustor: 0
4 Covariant / 协变
return type
1. 解决的问题
overridden vf 在 Base / Derived
中 return type 通常 相同
`为支持 overridden vf 在 Base / Derived 中`
return type 为 父 type / 子 type
=> 以 省去 不必要的 type conversion
引入 `Covariant Return Types`
2. 应用
// overridden vf 在 Derived 中 return type == Base 中 return type
virtual Base *
clone() const override
{
return new Derived(*this);
}
非 Covariant return type 时,
必须 用 pb + dynamic_cast<Derived *>
Derived* pd = new Derived();
Base* pb = pd->clone();
Derived *pd2 = dynamic_cast<Derived *>(pb);
引入 Covariant return type,
省去 不必要的 pb + dynamic_cast
// overridden vf 在 Derived 中 return type
// 是 Base 中 return type 的 子类
virtual Derived *
clone() const override
{
return new Derived(*this);
}
Derived *pd1 = new Derived();
Derived *pd2 = pd1->clone();
class Base
{
public:
virtual Base * clone() const
{
return new Base(*this);
}
};
`3. C++_Idioms`
https://en.m.wikibooks.org/wiki/More_C++_Idioms/Covariant_Return_Types
5 虚 dtor
1. Base dtor 非虚 的 问题
`销毁 obj 时, 不自动调用 其 所属 class 的 dtor 的 特例`
`1) Base ptr` 指向
newed Derived obj
`2) Derived 内 mem ptr` 指向
dynamic memory
3) Base dtor non-virtual
=>
delete Base ptr ( => destory Derived obj )
时, 调的 dtor
是 编译时绑定的 Bsae dtor
=>
`Derived 内 mem ptr` 所指
dynamic memory 未被释放

2. Base dtor 非虚 / 虚 : pbase->dtor
调 pbase 编译/运行 时
相应 type (Base / Derived) 的 dtor
class Base{
public:
~Base() { }
};
class Derived : public Base{
public:
Derived();
~Derived();
private:
int *ptr;
};
Derived::Derived() {
ptr = new int(0);
}
Derived::~Derived(){
delete ptr;
}
viod fun(Base* pbase){
delete pbase;
}
int main()
{
Base* pbase = new Derived();
fun(pbase);
}
6 两个函数间 overload override hide
1. func 同 原型
`同`
`1) 名`
`2) para`
`type / 个数 / 顺序 有不同, 则 不同 para`
`3) return type`
`4) const / virtual`
`2. 继承 virtual (function) 属性 的 2种情形`
`除 virtual` keyword 外, 若 `同 原型 / 协变 return type`
3. function 间 hide / overload / override
1) hide: 同名
, 不 care para/return type 等`
2) overload: 不同 para
`不 care return type`
compiler 对 overload func name 粉碎
3) override: 父 子 类 + vf ( 同 原型 / 协变 return type )
override 关键字 可用于 explicitly declare 函数覆盖
final + class / mem func: 不允许被 继承 / override
7 运行时 多态 的 条件
1) 子类 override 父类 vf ( 同 原型 / 协变 return type)
2) Base ptr / ref 调 Derived vf
8 virtual 与 static / friend / inline / dtor / ctor
virtual:
开启 动态绑定, 据
对象
的 动态类型
选择调 vf
(1) static mem func 属于类 而不是 对象
=> + virutal 报错
`static mem func 没 this 指针`
=> &obj 无法自动传入
=> 无法体现 多态
(2) friend 函数 不支持 继承 => 不能声明 为 vf
+ virtual = 报错
(3) inline
mem func: 编译时 绑定
+ virtual ( vf 运行时绑定 ) = 报错
(4) class 作 Base, dtor 要为 virtual
否则,
pb->dtor 调的是 Base dtor
=> Derived 内 dynamic memory 未被释放
(5) ctor 不能为 virtual
Ctor 中 某个点
对象的 (动态) 类型 `仅反映 当前已构造完成部分`
类层次 中 `某个 类 虚 Ctor`
会调用 `本类 或 更上层类` 中的 `Ctor 版本`
|
|/
error
对象
-> vptr -> vtbl -> 虚 ctor -> 构造出对象 => 矛盾
网友评论