C++中虚函数工作原理和(虚)继承类的内存占用大小计算-2

上一篇 / 下一篇  2012-08-21 09:26:30 / 个人分类:C++

51Testing软件测试网g6HA9S rc4ig E.l

  二、(虚)继承类的内存占用大小51Testing软件测试网hi3xsy't

C P h w'h)~H&H0  首先,平时所声明的类只是一种类型定义,它本身是没有大小可言的。 因此,如果用sizeof运算符对一个类型名操作,那得到的是具有该类型实体的大小。51Testing软件测试网(L0g {_:M%Q4q:g9M

Pyh8N'r8O]t7q0  计算一个类对象的大小时的规律:

~PXc9oF!`^+k0 51Testing软件测试网| _-k9P,u"j` \ O

  1、空类、单一继承的空类、多重继承的空类所占空间大小为:1(字节,下同);

.}&~z+ZHL"VoIl0

@5dr;G2U7}O0  2、一个类中,虚函数本身、成员函数(包括静态与非静态)和静态数据成员都是不占用类对象的存储空间的;

kv/u st'w C5wp3BJ0

E1o%Y3Z#Xr{Y0  3、因此一个对象的大小≥所有非静态成员大小的总和;

!r8p1D?,P&`~0 51Testing软件测试网5V2FS:W%R,Y:a6k1@

  4、当类中声明了虚函数(不管是1个还是多个),那么在实例化对象时,编译器会自动在对象里安插一个指针vPtr指向虚函数表VTable;

"a6z!MF&b0 51Testing软件测试网}|6t:oY V

  5、虚承继的情况:由于涉及到虚函数表和虚基表,会同时增加一个(多重虚继承下对应多个)vfPtr指针指向虚函数表vfTable和一个vbPtr指针指向虚基表vbTable,这两者所占的空间大小为:8(或8乘以多继承时父类的个数);51Testing软件测试网 h0QF'pT;P$l

*b4e z2ct0  6、在考虑以上内容所占空间的大小时,还要注意编译器下的“补齐”padding的影响,即编译器会插入多余的字节补齐;51Testing软件测试网{2O[ |x

,OT,H5|gl$u/L0  7、类对象的大小=各非静态数据成员(包括父类的非静态数据成员但都不包括所有的成员函数)的总和+ vfptr指针(多继承下可能不止一个)+vbptr指针(多继承下可能不止一个)+编译器额外增加的字节。

U^!G,^U0 51Testing软件测试网C3c2t:?2x6Fi#PB| _4H

  示例一:含有普通继承51Testing软件测试网 zi/a!c.r

51Testing软件测试网^6tNW u5eu"u:W

51Testing软件测试网%i)n0m4Z G`;RNJ

51Testing软件测试网*C(P,h R m~of

class A  
kpF A;u"p |zk0{  
6uWX0U z'Sr;n0}; 
51Testing软件测试网b1~'RK LdX W

51Testing软件测试网7HxPbA}_

class B   51Testing软件测试网 n#X@ `$d y)@!a
{
B?4Gq/v I_ e\#G0 char ch;  
,}X.Z1dDQs0 virtual void func0()  {  }
0z5~;N1uKtAmK0};
51Testing软件测试网1pd!e{2hr}&w"b%_

6CT'y:s'M:a0class C 
n5?|.kML0{
Rt#O `.iq t6g.j0 char ch1;51Testing软件测试网 fTj`+U"y-|G
 char ch2;
\;rt0n)j3K;jwd(C.T8_0 virtual void func()  {  } 
T!K4~PQse4H n[0 virtual void func1()  {  } 51Testing软件测试网T(U-L7Fogm)i
};
51Testing软件测试网*KUP?8xWr%E

&S#^YW6G0class D: public A, public C
dxAr6C7pcg0{   51Testing软件测试网!Eb!`4{]
 int d;  
?E9c @&r0 virtual void func()  {  }
#Vd \F+w]G/R:Ux6K0 virtual void func1()  {  }
X{5Z g1I @q0};  

1tx X_$G0

{oO5w\4ep bP0class E: public B, public C
lc1V Vt ~5v,_ zj0{  
.Il B_(F f0 int e;  
!_)n;}l$E/s;~5tY1f0 virtual void func0()  {  } 51Testing软件测试网q:x%]0GFO'M
 virtual void func1()  {  }
)qvvb].W{0};
51Testing软件测试网)Z:d `!h!K

x&Et v:i!o0Y&u0int main(void)
-^OJy[%w;fkt0{
4r bMrR4A:JK }0 cout<<"A="<<sizeof(A)<<endl;    //result=1
+wGLzN0 cout<<"B="<<sizeof(B)<<endl;    //result=8    51Testing软件测试网*M*]y \ol-~K
 cout<<"C="<<sizeof(C)<<endl;    //result=851Testing软件测试网9te*w8f(H\`
 cout<<"D="<<sizeof(D)<<endl;    //result=1251Testing软件测试网~U!VX{v}Q
 cout<<"E="<<sizeof(E)<<endl;    //result=2051Testing软件测试网W {&Nl,h&d&n.WJv
 return 0;
+O ]w:S7^-V"E.M0}

4|.{3qy'z/?051Testing软件测试网WQ^r1t"v%r

  前面三个A、B、C类的内存占用空间大小就不需要解释了,注意一下内存对齐就可以理解了。

H:VN%CS s/@0 51Testing软件测试网2Q_P1|9Wc _`

  求sizeof(D)的时候,需要明白,首先VPTR指向的虚函数表中保存的是类D中的两个虚函数的地址,然后存放基类C中的两个数据成员ch1、ch2,注意内存对齐,然后存放数据成员d,这样4+4+4=12。

+A2J,g6X"K0r-b3k0 51Testing软件测试网LL9z:CO{'E1_%p

  求sizeof(E)的时候,首先是类B的虚函数地址,然后类B中的数据成员,再然后是类C的虚函数地址,然后类C中的数据成员,最后是类E中的数据成员e,同样注意内存对齐,这样4+4+4+4+4=20。

n+v}n"?x(V&M0

z9`O#D"[;C"lj.tYU0  示例二:含有虚继承51Testing软件测试网6I~#Pa|7q!C

Y'x8Q+Aa {'u*H:z:uD%]0 51Testing软件测试网V n,},q3\!]K

51Testing软件测试网+n|M5oN!D4{r"tf

class CommonBase
t4K!|B3Aj8u0{51Testing软件测试网Y?[6[:C:{%{9\
 int co;51Testing软件测试网lL:|W@6j F Y
};

`;k&IaQG^0

t2n-IRt$} G \5w/r0class Base1: virtual public CommonBase51Testing软件测试网-K&t^pK
{51Testing软件测试网 [%n}/qRK!A
public:
0?Kt4h$m0 virtual void print1() {  }51Testing软件测试网(\ Q}EekD
 virtual void print2() {  }
YwCq.j#gU9a0private:
,e.NQ wsj/\f0 int b1;
}Y#n5A _0};
51Testing软件测试网7bu Ywc?_%oQ

;z2`E$U1|U'XK8``0class Base2: virtual public CommonBase51Testing软件测试网Fvr4G Av0y"q
{51Testing软件测试网"VtZVF
public:
h5_xjnV,f+Xd0 virtual void dump1() {  }
3Z8Q3s0T9L:w8X1qz0 virtual void dump2() {  }
4pu] |?4z.|o0private:51Testing软件测试网HE/vB&pn{y
 int b2;51Testing软件测试网3Y;P)MK4U[*N5aj5{
};

Hw?3DVc0

tGn'X#q3J$t8T0class Derived: public Base1, public Base251Testing软件测试网$j M Tizpb`fNf
{51Testing软件测试网(o'z{?)H(zl T g B0w
public:
@jdH)I XSC0 void print2() {  }51Testing软件测试网I]},MMp!X
 void dump2() {  }
1\,q#ez \n z4So0private:51Testing软件测试网,`Bm2G^X2Rp"q+e
 int d;
Y.Qz?l8D*H(p l#yu0};

F@)q%Yr W0
51Testing软件测试网5MIqeB-\

  sizeof(Derived)=32,其在内存中分布的情况如下:

WQPm2F}n0

Z+r/v5n5i0e*l0 51Testing软件测试网R.i/@*D,?Fi%k tW

class Derived size(32):51Testing软件测试网w/E t8IM
     +---
%Z.ZT#r.dT{0     | +--- (base class Base1)51Testing软件测试网J1bX9H.l4l#Ds$x
 | | {vfptr}
S^rq }1T1V2um"l0 | | {vbptr}51Testing软件测试网dKx~Y'}5}%^9^
 | | b151Testing软件测试网 |]z l8[6OOZuF
     | +---51Testing软件测试网&^U [\0J
     | +--- (base class Base2)51Testing软件测试网z3CR I4z)\ ny6~
 | | {vfptr}
+C!G F!AGS)n[0 | | {vbptr}51Testing软件测试网-kf,K J t'H#@#e |
 | | b2
g.v8Ymx8_0    | +---
oA5~ ~'{F0 | d
%ZX8P'^ c+l0    +---51Testing软件测试网FG7R\a+G Y$?
    +--- (virtual base CommonBase)51Testing软件测试网UV o'E6PANVg8Qe
 | co51Testing软件测试网 zl7^Z$awJL3V
    +---
51Testing软件测试网.GU Y+Ywauq n

  示例3:

8p(dy M"Qu'tR#O;M0 51Testing软件测试网4ak!RY/P ~9F$~/_

51Testing软件测试网4d;Cl{$XSn[9c

51Testing软件测试网 V`rM'x(H)^*~t#IO

class A
ssJ)}d0{51Testing软件测试网"yB0^9i0dm
public:
7DD?8|f D'c|^@6W f0 virtual void aa() {  }
[!g)T-f8|9?J0 virtual void aa2() {  }51Testing软件测试网0Wka\5Z(~`)L
private:
?4A,Fx+i0 char ch[3];51Testing软件测试网DAV x:K}&u
};

e8y9D `I)R'{K3]~m0

|-UtTF-q&m8^+T5m0class B: virtual public A51Testing软件测试网7|p e~8U.v(N
{51Testing软件测试网 VRM}[Z
public:51Testing软件测试网!G DlYSN0T
 virtual void bb() {  }51Testing软件测试网 Y8h-C P%c eXr Q!x
 virtual void bb2() {  }51Testing软件测试网5B7g"U,w~
};

8b uhqCr(v,UZ0

P(J:^IFfs0int main(void)51Testing软件测试网3b.J'C9G(X8SbG
{
&xp VD6r0 cout<<"A's size is "<<sizeof(A)<<endl;51Testing软件测试网#?'NzfL)a
 cout<<"B's size is "<<sizeof(B)<<endl;
*de8ta-I!W.e;v7\0 return 0;51Testing软件测试网yie QS9w
}

+U)t.AS7bUegaw0

q3kxA ~0  执行结果:A's size is 851Testing软件测试网%Hp+]P.Ce

f*Ur7v(g0  B's size is 16

_;yC2F+@cw`0

A~TqF0  说明:对于虚继承,类B因为有自己的虚函数,所以它本身有一个虚指针,指向自己的虚表。另外,类B虚继承类A时,首先要通过加入一个虚指针来指向父类A,然后还要包含父类A的所有内容。因此是4+4+8=16。51Testing软件测试网N K8?X2x%bo2G


TAG:

 

评分:0

我来说两句

Open Toolbar