c++ 对象的内存布局
【本文链接】
http://www.cnblogs.com/hellogiser/p/class-memory-layout.html
【分析】
对象的影响因素
简而言之,一个类可能会有如下的影响因素:
1)成员变量
2)虚函数(产生虚函数表)
3)单一继承(只继承于一个类)
4)多重继承(继承多个类)
5)重复继承(继承的多个父类中其父类有相同的超类)
6)虚拟继承(使用virtual方式继承,为了保证继承后父类的内存布局只会存在一份)
上述的东西通常是C++这门语言在语义方面对对象内部的影响因素,当然,还会有编译器的影响(比如优化),还有字节对齐的影响。在这里我们都不讨论,我们只讨论C++语言上的影响。
本篇文章着重讨论下述几个情况下的C++对象的内存布局情况。
1)单一的一般继承(带成员变量、虚函数、虚函数覆盖)
2)单一的虚拟继承(带成员变量、虚函数、虚函数覆盖)
3)多重继承(带成员变量、虚函数、虚函数覆盖)
4)重复多重继承(带成员变量、虚函数、虚函数覆盖)
5)钻石型的虚拟多重继承(带成员变量、虚函数、虚函数覆盖)
(1)单一的一般继承
下面,我们假设有如下所示的一个继承关系:
请注意,在这个继承关系中,父类,子类,孙子类都有自己的一个成员变量。而了类覆盖了父类的f()方法,孙子类覆盖了子类的g_child()及其超类的f()。
可见以下几个方面:
1)虚函数表在最前面的位置。
2)成员变量根据其继承和声明顺序依次放在后面。
3)在单一的继承中,被override的虚函数在虚函数表中得到了更新。(Child的f覆盖Parent的f函数,然后GrandChild的f覆盖Child的f;GrandChild的g_child覆盖Child的g_child)
代码验证如下
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 |
/*
version: 1.0 author: hellogiser blog: http://www.cnblogs.com/hellogiser date: 2014/9/29 */ #include "stdafx.h" #include <iostream> using namespace std; class Parent { public: int iparent; Parent (): iparent (10) {} virtual void f() { cout << " Parent::f()" << endl; } virtual void g() { cout << " Parent::g()" << endl; } virtual void h() { cout << " Parent::h()" << endl; } }; class Child : public Parent { public: int ichild; Child(): ichild(100) {} virtual void f() { cout << "Child::f()" << endl; } virtual void g_child() { cout << "Child::g_child()" << endl; } virtual void h_child() { cout << "Child::h_child()" << endl; } }; class GrandChild : public Child { public: int igrandchild; GrandChild(): igrandchild(1000) {} virtual void f() { cout << "GrandChild::f()" << endl; } virtual void g_child() { cout << "GrandChild::g_child()" << endl; } virtual void h_grandchild() { cout << "GrandChild::h_grandchild()" << endl; } }; typedef void(*Fun)(void); /* vptr ---> Parent::f(),Parent::g(),Parent::h() iparent */ void test_parent() { Parent obj; Fun pFun; int **pVtab = (int **)(&obj); int n = 3; cout << "[0] Parent::_vptr->" << endl; for (int i = 0; i < n; i++) { pFun = (Fun)pVtab[0][i]; cout << "------[" << i << "] "; pFun(); } cout << "[1] Parent.iparent = " << (int)pVtab[1] << endl; cout << "============================================" << endl; } /* vptr ---> Child::f(),Parent::g(),Parent::h(),Child::g_child(),Child::h_child() iparent ichild */ void test_child() { Child obj; Fun pFun; int **pVtab = (int **)(&obj); int n = 5; cout << "[0] Child::_vptr->" << endl; for (int i = 0; i < n; i++) { pFun = (Fun)pVtab[0][i]; cout << "------[" << i << "] "; pFun(); } cout << "[1] Parent.iparent = " << (int)pVtab[1] << endl; cout << "[2] Child.ichild = " << (int)pVtab[2] << endl; //cout << "[3] GrandChild.igrandchild = " << (int)pVtab[3] << endl; cout << "============================================" << endl; } /* vptr ---> GrandChild::f(),Parent::g(),Parent::h(),GrandChild::g_child(),Child::h_child() iparent ichild igrandchild */ void test_grandchild() { GrandChild obj; Fun pFun; int **pVtab = (int **)(&obj); int n = 5; cout << "[0] GrandChild::_vptr->" << endl; for (int i = 0; i < n; i++) { pFun = (Fun)pVtab[0][i]; cout << "------[" << i << "] "; pFun(); } cout << "[1] Parent.iparent = " << (int)pVtab[1] << endl; cout << "[2] Child.ichild = " << (int)pVtab[2] << endl; cout << "[3] GrandChild.igrandchild = " << (int)pVtab[3] << endl; cout << "============================================" << endl; } int main() { test_parent(); test_child(); test_grandchild(); return 0; } /* [0] Parent::_vptr-> ------[0] Parent::f() ------[1] Parent::g() ------[2] Parent::h() [1] Parent.iparent = 10 ============================================ [0] Child::_vptr-> ------[0] Child::f() ------[1] Parent::g() ------[2] Parent::h() ------[3] Child::g_child() ------[4] Child::h_child() [1] Parent.iparent = 10 [2] Child.ichild = 100 ============================================ [0] GrandChild::_vptr-> ------[0] GrandChild::f() ------[1] Parent::g() ------[2] Parent::h() ------[3] GrandChild::g_child() ------[4] Child::h_child() [1] Parent.iparent = 10 [2] Child.ichild = 100 [3] GrandChild.igrandchild = 1000 ============================================ */ |
(2)多重继承
下面,再让我们来看看多重继承中的情况,假设有下面这样一个类的继承关系。注意:子类只overwrite了父类的f()函数,而还有一个是自己的函数(我们这样做的目的是为了用g1()作为一个标记来标明子类的虚函数表)。而且每个类中都有一个自己的成员变量:
我们的类继承的源代码如下所示:父类的成员初始为10,20,30,子类的为100
使用图片表示是下面这个样子:
我们可以看到:
1) 每个父类都有自己的虚表。
2) 子类的成员函数被放到了第一个父类的表中。
3) 内存布局中,其父类布局依次按声明顺序排列。
4) 每个父类的虚表中的f()函数都被override成了子类的f()。这样做就是为了解决不同的父类类型的指针指向同一个子类实例,而能够调用到实际的函数。
代码验证如下
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
/*
version: 1.0 author: hellogiser blog: http://www.cnblogs.com/hellogiser date: 2014/9/29 */ #include "stdafx.h" #include <iostream> using namespace std; class Base1 { public: int ibase1; Base1(): ibase1(10) {} virtual void f() { cout << "Base1::f()" << endl; } virtual void g() { cout << "Base1::g()" << endl; } virtual void h() { cout << "Base1::h()" << endl; } }; class Base2 { public: int ibase2; Base2(): ibase2(20) {} virtual void f() { cout << "Base2::f()" << endl; } virtual void g() { cout << "Base2::g()" << endl; } virtual void h() { cout << "Base2::h()" << endl; } }; class Base3 { public: int ibase3; Base3(): ibase3(30) {} virtual void f() { cout << "Base3::f()" << endl; } virtual void g() { cout << "Base3::g()" << endl; } virtual void h() { cout << "Base3::h()" << endl; } }; class Derive : public Base1, public Base2, public Base3 { public: int iderive; Derive(): iderive(100) {} virtual void f() { cout << "Derive::f()" << endl; } virtual void g1() { cout << "Derive::g1()" << endl; } }; typedef void(*Fun)(void); /* Base1 vptr---> Derive::f(),Base1::g(),Base1::h(),Derive::g1() ibase1 Base2 vptr--->Derive::f(),Base2::g(),Base2::h() ibase2 Base3 vptr--->Derive::f(),Base3::g(),Base3::h() ibase3 iderive */ void test() { Derive obj; Fun pFun; int **pVtab = (int **)(&obj); int n = 4; cout << "[0] Base1::_vptr->" << endl; for (int i = 0; i < n; i++) { pFun = (Fun)pVtab[0][i]; cout << "------[" << i << "] "; pFun(); } cout << "[1] Base1.ibase1 = " << (int)pVtab[1] << endl; cout << "============================================" << endl; n = 3; cout << "[2] Base2::_vptr->" << endl; for (int i = 0; i < n; i++) { pFun = (Fun)pVtab[2][i]; cout << "------[" << i << "] "; pFun(); } cout << "[3] Base2.ibase2 = " << (int)pVtab[3] << endl; cout << "============================================" << endl; n = 3; cout << "[4] Base3::_vptr->" << endl; for (int i = 0; i < n; i++) { pFun = (Fun)pVtab[4][i]; cout << "------[" << i << "] "; pFun(); } cout << "[5] Base3.ibase3 = " << (int)pVtab[5] << endl; cout << "============================================" << endl; cout << "[6] Derive.iderive = " << (int)pVtab[6] << endl; } int main() { test(); return 0; } /* [0] Base1::_vptr-> ------[0] Derive::f() ------[1] Base1::g() ------[2] Base1::h() ------[3] Derive::g1() [1] Base1.ibase1 = 10 ============================================ [2] Base2::_vptr-> ------[0] Derive::f() ------[1] Base2::g() ------[2] Base2::h() [3] Base2.ibase2 = 20 ============================================ [4] Base3::_vptr-> ------[0] Derive::f() ------[1] Base3::g() ------[2] Base3::h() [5] Base3.ibase3 = 30 ============================================ [6] Derive.iderive = 100 */ |
(3)重复继承
下面我们再来看看,发生重复继承的情况。所谓重复继承,也就是某个基类被间接地重复继承了多次。
下图是一个继承图,我们重载了父类的f()函数。
下面是对于子类实例中的虚函数表的图:
我们可以看见,最顶端的父类B其成员变量存在于B1和B2中,并被D给继承下去了。而在D中,其有B1和B2的实例,于是B的成员在D的实例中存在两份,一份是B1继承而来的,另一份是B2继承而来的。所以,如果我们使用以下语句,则会产生二义性编译错误:
1
2 3 4 5 6 7 |
void test_error()
{ D d; // d.ib = 1; //ERROR d.B1::ib = 1; // ok d.B2::ib = 100; // ok } |
注意,上面例程中的最后两条语句存取的是两个变量。虽然我们消除了二义性的编译错误,但B类在D中还是有两个实例,这种继承造成了数据的重复,我们叫这种继承为重复继承。重复的基类数据成员可能并不是我们想要的。所以,C++引入了虚基类的概念。
代码验证如下
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 |
/*
version: 1.0 author: hellogiser blog: http://www.cnblogs.com/hellogiser date: 2014/9/29 */ #include "stdafx.h" #include <iostream> using namespace std; class B { public: int ib; char cb; public: B(): ib(0), cb('B') {} virtual void f() { cout << "B::f()" << endl; } virtual void Bf() { cout << "B::Bf()" << endl; } }; class B1 : public B { public: int ib1; char cb1; public: B1(): ib1(11), cb1('1') {} virtual void f() { cout << "B1::f()" << endl; } virtual void f1() { cout << "B1::f1()" << endl; } virtual void Bf1() { cout << "B1::Bf1()" << endl; } }; class B2: public B { public: int ib2; char cb2; public: B2(): ib2(12), cb2('2') {} virtual void f() { cout << "B2::f()" << endl; } virtual void f2() { cout << "B2::f2()" << endl; } virtual void Bf2() { cout << "B2::Bf2()" << endl; } }; class D : public B1, public B2 { public: int id; char cd; public: D(): id(100), cd('D') {} virtual void f() { cout << "D::f()" << endl; } virtual void f1() { cout << "D::f1()" << endl; } virtual void f2() { cout << "D::f2()" << endl; } virtual void Df() { cout << "D::Df()" << endl; } }; typedef void(*Fun)(void); void test_error() { D d; // d.ib = 1; //ERROR d.B1::ib = 1; // ok d.B2::ib = 100; // ok } /* B1.vptr --->D::f,B::Bf,D::f1,B1::Bf1,D::Df B.ib B.cb B1.ib1 B1.cb1 B2.vptr --->D::f,B::Bf,D::f2,B2::Bf2 B.ib B.cb B2.ib2 B2.cb2 D.id D.cd */ void test_public() { D obj; Fun pFun; int **pVtab = (int **)(&obj); int n = 5; cout << "[0] D::B1::_vptr->" << endl; for (int i = 0; i < n; i++) { pFun = (Fun)pVtab[0][i]; cout << "------[" << i << "] "; pFun(); } cout << "[1] B.ib = " << (int)pVtab[1] << endl; cout << "[2] B.cb = " << (char)pVtab[2] << endl; cout << "[3] B1.ib1 = " << (int)pVtab[3] << endl; cout << "[4] B1.cb1 = " << (char)pVtab[4] << endl; n = 4; cout << "[5] D::B2::_vptr->" << endl; for (int i = 0; i < n; i++) { pFun = (Fun)pVtab[5][i]; cout << "------[" << i << "] "; pFun(); } cout << "[6] B.ib = " << (int)pVtab[6] << endl; cout << "[7] B.cb = " << (char)pVtab[7] << endl; cout << "[8] B2.ib2 = " << (int)pVtab[8] << endl; cout << "[9] B2.cb2 = " << (char)pVtab[9] << endl; cout << "[10] D.id = " << (int)pVtab[10] << endl; cout << "[11] D.cd = " << (char)pVtab[11] << endl; } void test_virtual_public() { } int main() { test_public(); return 0; } /* [0] D::B1::_vptr-> ------[0] D::f() ------[1] B::Bf() ------[2] D::f1() ------[3] B1::Bf1() ------[4] D::Df() [1] B.ib = 0 [2] B.cb = B [3] B1.ib1 = 11 [4] B1.cb1 = 1 [5] D::B2::_vptr-> ------[0] D::f() ------[1] B::Bf() ------[2] D::f2() ------[3] B2::Bf2() [6] B.ib = 0 [7] B.cb = B [8] B2.ib2 = 12 [9] B2.cb2 = 2 [10] D.id = 100 [11] D.cd = D */ |
(4)钻石型多重虚拟继承
虚拟继承的出现就是为了解决重复继承中多个间接父类的问题的。钻石型的结构是其最经典的结构。也是我们在这里要讨论的结构:
上述的“重复继承”只需要把B1和B2继承B的语法中加上virtual 关键,就成了虚拟继承,其继承图如下所示:
上图和前面的“重复继承”中的类的内部数据和接口都是完全一样的,只是我们采用了虚拟继承:其省略后的源码如下所示:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
class B
{ …… }; class B1 : virtual public B { …… }; class B2: virtual public B { …… }; class D : public B1, public B2 { …… }; |
代码验证如下
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 |
/*
version: 1.0 author: hellogiser blog: http://www.cnblogs.com/hellogiser date: 2014/9/29 */ #include "stdafx.h" #include <iostream> using namespace std; class B { public: int ib; char cb; public: B(): ib(0), cb('B') {} virtual void f() { cout << "B::f()" << endl; } virtual void Bf() { cout << "B::Bf()" << endl; } }; class B1 : virtual public B { public: int ib1; char cb1; public: B1(): ib1(11), cb1('1') {} virtual void f() { cout << "B1::f()" << endl; } virtual void f1() { cout << "B1::f1()" << endl; } virtual void Bf1() { cout << "B1::Bf1()" << endl; } }; class B2: virtual public B { public: int ib2; char cb2; public: B2(): ib2(12), cb2('2') {} virtual void f() { cout << "B2::f()" << endl; } virtual void f2() { cout << "B2::f2()" << endl; } virtual void Bf2() { cout << "B2::Bf2()" << endl; } }; class D : public B1, public B2 { public: int id; char cd; public: D(): id(100), cd('D') {} virtual void f() { cout << "D::f()" << endl; } virtual void f1() { cout << "D::f1()" << endl; } virtual void f2() { cout << "D::f2()" << endl; } virtual void Df() { cout << "D::Df()" << endl; } }; typedef void(*Fun)(void); void test_error() { D d; d.ib = 1; //OK } /* B1.vptr --->D::f1,B1::Bf1,D::Df B1.vbptr (-4) B1.ib1 B1.cb1 B2.vptr --->D::f2,B2::Bf2 B2.vbptr (-4) B2.ib2 B2.cb2 D.id D.cd NULL (delimiter) B.vptr --->D::f,B::Bf B.ib B.cb */ void test_virtual_public() { D obj; Fun pFun; int **pVtab = (int **)(&obj); int n = 3; cout << "[0] D::B1::_vptr->" << endl; for (int i = 0; i < n; i++) { pFun = (Fun)pVtab[0][i]; cout << "------[" << i << "] "; pFun(); } cout << "[1] B1::_vbptr = " << (int)pVtab[1] << " " << *pVtab[1] << endl; cout << "[2] B1.ib1 = " << (int)pVtab[2] << endl; cout << "[3] B1.cb1 = " << (char)pVtab[3] << endl; n = 2; cout << "[4] D::B2::_vptr->" << endl; for (int i = 0; i < n; i++) { pFun = (Fun)pVtab[4][i]; cout << "------[" << i << "] "; pFun(); } cout << "[5] B2::_vbptr = " << (int)pVtab[5] << " " << *pVtab[5] << endl; cout << "[6] B2.ib2 = " << (int)pVtab[6] << endl; cout << "[7] B2.cb2 = " << (char)pVtab[7] << endl; cout << "[8] D.id = " << (int)pVtab[8] << endl; cout << "[9] D.cd = " << (char)pVtab[9] << endl; cout << "[10] NULL =0x " << pVtab[10] << endl; n = 2; cout << "[11] D::B::_vptr->" << endl; for (int i = 0; i < n; i++) { pFun = (Fun)pVtab[11][i]; pFun(); } cout << "[12] B.ib = " << (int)pVtab[12] << endl; cout << "[13] B.cb = " << (char)pVtab[13] << endl; } int main() { test_virtual_public(); return 0; } /* [0] D::B1::_vptr-> ------[0] D::f1() ------[1] B1::Bf1() ------[2] D::Df() [1] B1::_vbptr = 10769056 -4 [2] B1.ib1 = 11 [3] B1.cb1 = 1 [4] D::B2::_vptr-> ------[0] D::f2() ------[1] B2::Bf2() [5] B2::_vbptr = 10769048 -4 [6] B2.ib2 = 12 [7] B2.cb2 = 2 [8] D.id = 100 [9] D.cd = D [10] NULL =0x 00000000 [11] D::B::_vptr-> D::f() B::Bf() [12] B.ib = 0 [13] B.cb = B */ |
从上述结果,我们可以看出,B1和B2的继承方式改为virtual继承之后,内存布局发生了3个重大变化:
1) 首先B1,然后是B2,接着是D,而B这个超类的实例都放在最后的位置(B1和B2的公共部分B被提取出来放在D实例的最后)
2) B1和B2的vptr之后添加了一个字段vbptr,其值为-4(表示vptr相对vbptr地址的偏移量)
3)在D和最后的B之间添加了一个NULL分隔符将其布局分开。(只有派生类覆盖了基类的virtual函数,才有分隔符,否则没有分隔符)
【附录】
(1)单一继承vs单一virtual继承
【单一继承】
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
/*
version: 1.0 author: hellogiser blog: http://www.cnblogs.com/hellogiser date: 2014/9/29 */ #include "stdafx.h" #include <iostream> using namespace std; class Base { public: int ibase; public: Base(): ibase(10) {} virtual void f() { cout << "Base::f()" << endl; } virtual void g() { cout << "Base::g()" << endl; } virtual void h() { cout << "Base::h()" << endl; } }; class Derived : public Base { public: int iderived; public: Derived(): iderived(100) {} virtual void f() { cout << "Derived::f()" << endl; } virtual void g2() { cout << "Derived::g2()" << endl; } virtual void h2() { cout << "Derived::h2()" << endl; } }; typedef void(*Fun)(void); /* Base::vptr--->Derived::f(),Base::g(),Base::h(),Derived::g2(),Derived::h2() ibase iderived */ void test_public() { Derived obj; Fun pFun; int **pVtab = (int **)(&obj); int n = 5; cout << "[0] Base::_vptr->" << endl; for (int i = 0; i < n; i++) { pFun = (Fun)pVtab[0][i]; cout << "------[" << i << "] "; pFun(); } cout << "[1] Base.ibase = " << (int)pVtab[1] << endl; cout << "[2] Derived.iderived = " << (int)pVtab[2] << endl; } int main() { test_public(); return 0; } /* [0] Base::_vptr-> ------[0] Derived::f() ------[1] Base::g() ------[2] Base::h() ------[3] Derived::g2() ------[4] Derived::h2() [1] Base.ibase = 10 [2] Derived.iderived = 100 */ |
【单一virtual继承】
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
/*
version: 1.0 author: hellogiser blog: http://www.cnblogs.com/hellogiser date: 2014/9/29 */ #include "stdafx.h" #include <iostream> using namespace std; class Base { public: int ibase; public: Base(): ibase(10) {} virtual void f() { cout << "Base::f()" << endl; } virtual void g() { cout << "Base::g()" << endl; } virtual void h() { cout << "Base::h()" << endl; } }; class Derived : virtual public Base { public: int iderived; public: Derived(): iderived(100) {} virtual void f() { cout << "Derived::f()" << endl; } virtual void g2() { cout << "Derived::g2()" << endl; } virtual void h2() { cout << "Derived::h2()" << endl; } }; typedef void(*Fun)(void); /* Derived::vptr--->Derived::g2(),Derived::h2() Derived::vbptr iderived NULL (demiliter) Base::vptr--->Derived::f(),Base::g(),Base::h() ibase */ void test_virtual_public() { Derived obj; Fun pFun; int **pVtab = (int **)(&obj); int n = 2; cout << "[0] Derived::_vptr->" << endl; for (int i = 0; i < n; i++) { pFun = (Fun)pVtab[0][i]; cout << "------[" << i << "] "; pFun(); } cout << "[1] Derived::_vbptr = " << (int)pVtab[1] << " " << *pVtab[1] << endl; cout << "[2] Derived.iderived = " << (int)pVtab[2] << endl; cout << "[3] NULL =0x " << pVtab[3] << endl; n = 3; cout << "[4] Base::_vptr->" << endl; for (int i = 0; i < n; i++) { pFun = (Fun)pVtab[4][i]; pFun(); } cout << "[5] Base.ibase = " << (int)pVtab[5] << endl; } int main() { test_virtual_public(); return 0; } /* [0] Derived::_vptr-> ------[0] Derived::g2() ------[1] Derived::h2() [1] Derived::_vbptr = 17449756 -4 [2] Derived.iderived = 100 [3] NULL =0x 00000000 [4] Base::_vptr-> Derived::f() Base::g() Base::h() [5] Base.ibase = 10 */ |
(2)单一virtual继承的4种情况
假设Base有3个虚函数f,g,h
1)Derived没有覆盖基类Base的任何虚函数,Derived没有定义新的虚函数,内存布局如下
1
2 3 4 5 6 7 8 9 10 11 12 13 14 |
//virtual void f() { cout << "Derived::f()" << endl;} //virtual void g2() { cout << "Derived::g2()" << endl;} //virtual void h2() { cout << "Derived::h2()" << endl;} /* [0] Derived::_vbptr = 19088092 0 [1] Derived.iderived = 100 [2] Base::_vptr-> Base::f() Base::g() Base::h() [3] Base.ibase = 10 */ |
2)Derived没有覆盖基类Base的任何虚函数,但是Derived定义了新的虚函数g2和h2,内存布局如下
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
//virtual void f() { cout << "Derived::f()" << endl;} virtual void g2() { cout << "Derived::g2()" << endl; } virtual void h2() { cout << "Derived::h2()" << endl; } /* [0] Derived::_vptr -> Derived::g2() Derived::h2() [1] Derived::_vbptr = 20857576 -4 [2] Derived.iderived = 100 [3] Base::_vptr-> Base::f() Base::g() Base::h() [4] Base.ibase = 10 */ |
3)Derived覆盖了基类Base的某个虚函数f,但是Derived没有定义新的虚函数,内存布局如下
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
virtual void f() { cout << "Derived::f()" << endl; } //virtual void g2() { cout << "Derived::g2()" << endl;} //virtual void h2() { cout << "Derived::h2()" << endl;} /* [0] Derived::_vbptr = 11748060 0 [1] Derived.iderived = 100 [2] NULL =0x 00000000 [3] Base::_vptr-> Derived::f() Base::g() Base::h() [4] Base.ibase = 10 */ |
4)Derived覆盖了基类Base的某个虚函数f,同时Derived定义了新的虚函数g2和h2,内存布局如下
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
virtual void f() { cout << "Derived::f()" << endl; } virtual void g2() { cout << "Derived::g2()" << endl; } virtual void h2() { cout << "Derived::h2()" << endl; } /* [0] Derived::_vptr -> Derived::g2() Derived::h2() [1] Derived::_vbptr = 10441448 -4 [2] Derived.iderived = 100 [3] NULL =0x 00000000 [4] Base::_vptr-> Derived::f() Base::g() Base::h() [5] Base.ibase = 10 */ |
由此可见:
Derived是否覆盖Base的虚函数?
1)Derived没有覆盖基类Base的任何虚函数,内存布局中Derived和Base部分没有分隔符NULL。
2)Derived覆盖基类Base的某个虚函数f,内存布局中Derived和Base部分添加了分隔符NULL。
Derived是否定义新的虚函数?
1)Derived定义了新的虚函数g2和h2,内存布局的前2个位置依次为vfptr和vbptr,且vbptr的值为-4,表示vfptr和vbptr的偏移量为-4
2)Derived没有定义新的虚函数,内存布局的vfptr和vbptr退化为一个,且vbptr的值为0,表示vfptr和vbptr的偏移量为0,即vfptr和vbptr重合了。
完整代码如下
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 |
/*
version: 1.0 author: hellogiser blog: http://www.cnblogs.com/hellogiser date: 2014/9/29 */ #include "stdafx.h" #include <iostream> using namespace std; class Base { public: int ibase; public: Base(): ibase(10) {} virtual void f() { cout << "Base::f()" << endl; } virtual void g() { cout << "Base::g()" << endl; } virtual void h() { cout << "Base::h()" << endl; } }; class Derived : virtual public Base { public: int iderived; public: Derived(): iderived(100) {} virtual void f() { cout << "Derived::f()" << endl; } virtual void g2() { cout << "Derived::g2()" << endl; } virtual void h2() { cout << "Derived::h2()" << endl; } }; typedef void(*Fun)(void); /* //virtual void f() { cout << "Derived::f()" << endl;} //virtual void g2() { cout << "Derived::g2()" << endl;} //virtual void h2() { cout << "Derived::h2()" << endl;} */ /* [0] Derived::_vbptr = 19088092 0 [1] Derived.iderived = 100 [2] Base::_vptr-> Base::f() Base::g() Base::h() [3] Base.ibase = 10 */ void test_virtual_public_1() { Derived obj; Fun pFun; int **pVtab = (int **)(&obj); int n = 0; cout << "[0] Derived::_vbptr = " << (int)pVtab[0] << " " << *pVtab[0] << endl; cout << "[1] Derived.iderived = " << (int)pVtab[1] << endl; n = 3; cout << "[2] Base::_vptr->" << endl; for (int i = 0; i < n; i++) { pFun = (Fun)pVtab[2][i]; pFun(); } cout << "[3] Base.ibase = " << (int)pVtab[3] << endl; } /* //virtual void f() { cout << "Derived::f()" << endl;} virtual void g2() { cout << "Derived::g2()" << endl;} virtual void h2() { cout << "Derived::h2()" << endl;} */ /* [0] Derived::_vptr -> Derived::g2() Derived::h2() [1] Derived::_vbptr = 20857576 -4 [2] Derived.iderived = 100 [3] Base::_vptr-> Base::f() Base::g() Base::h() [4] Base.ibase = 10 */ void test_virtual_public_2() { Derived obj; Fun pFun; int **pVtab = (int **)(&obj); int n = 2; cout << "[0] Derived::_vptr ->" << endl; for (int i = 0; i < n; i++) { pFun = (Fun)pVtab[0][i]; pFun(); } cout << "[1] Derived::_vbptr = " << (int)pVtab[1] << " " << *pVtab[1] << endl; cout << "[2] Derived.iderived = " << (int)pVtab[2] << endl; n = 3; cout << "[3] Base::_vptr->" << endl; for (int i = 0; i < n; i++) { pFun = (Fun)pVtab[3][i]; pFun(); } cout << "[4] Base.ibase = " << (int)pVtab[4] << endl; } /* virtual void f() { cout << "Derived::f()" << endl;} //virtual void g2() { cout << "Derived::g2()" << endl;} //virtual void h2() { cout << "Derived::h2()" << endl;} */ /* [0] Derived::_vbptr = 11748060 0 [1] Derived.iderived = 100 [2] NULL =0x 00000000 [3] Base::_vptr-> Derived::f() Base::g() Base::h() [4] Base.ibase = 10 */ void test_virtual_public_3() { Derived obj; Fun pFun; int **pVtab = (int **)(&obj); int n = 0; cout << "[0] Derived::_vbptr = " << (int)pVtab[0] << " " << *pVtab[0] << endl; cout << "[1] Derived.iderived = " << (int)pVtab[1] << endl; cout << "[2] NULL =0x " << pVtab[2] << endl; n = 3; cout << "[3] Base::_vptr->" << endl; for (int i = 0; i < n; i++) { pFun = (Fun)pVtab[3][i]; pFun(); } cout << "[4] Base.ibase = " << (int)pVtab[4] << endl; } /* virtual void f() { cout << "Derived::f()" << endl;} virtual void g2() { cout << "Derived::g2()" << endl;} virtual void h2() { cout << "Derived::h2()" << endl;} */ /* [0] Derived::_vptr -> Derived::g2() Derived::h2() [1] Derived::_vbptr = 10441448 -4 [2] Derived.iderived = 100 [3] NULL =0x 00000000 [4] Base::_vptr-> Derived::f() Base::g() Base::h() [5] Base.ibase = 10 */ void test_virtual_public_4() { Derived obj; Fun pFun; int **pVtab = (int **)(&obj); int n = 2; cout << "[0] Derived::_vptr ->" << endl; for (int i = 0; i < n; i++) { pFun = (Fun)pVtab[0][i]; pFun(); } cout << "[1] Derived::_vbptr = " << (int)pVtab[1] << " " << *pVtab[1] << endl; cout << "[2] Derived.iderived = " << (int)pVtab[2] << endl; cout << "[3] NULL =0x " << pVtab[3] << endl; n = 3; cout << "[4] Base::_vptr->" << endl; for (int i = 0; i < n; i++) { pFun = (Fun)pVtab[4][i]; pFun(); } cout << "[5] Base.ibase = " << (int)pVtab[5] << endl; } int main() { test_virtual_public_4(); return 0; } |
【参考】