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

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

51Testing软件测试网WC5^1C%cOr

  二、(虚)继承类的内存占用大小

? \7i6e Ia r9W%]]0

_!a m6`s F%@qv0  首先,平时所声明的类只是一种类型定义,它本身是没有大小可言的。 因此,如果用sizeof运算符对一个类型名操作,那得到的是具有该类型实体的大小。51Testing软件测试网 _?1\b9n|q

51Testing软件测试网+s1e9qPszm

  计算一个类对象的大小时的规律:51Testing软件测试网r+e%b"^T2X8sw?

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

zF/v$ZW-r0 51Testing软件测试网){&h&s8M0m2z7ia

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

5d!e3O G5Zh9b0

9wH6e6Cy(s0  3、因此一个对象的大小≥所有非静态成员大小的总和;

,hMv-r^beL0 51Testing软件测试网-iz)l1V3S RF)[-c;P6m

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

&GnMjXqaf`0

-fJ~3Anc-M)Tz`0  5、虚承继的情况:由于涉及到虚函数表和虚基表,会同时增加一个(多重虚继承下对应多个)vfPtr指针指向虚函数表vfTable和一个vbPtr指针指向虚基表vbTable,这两者所占的空间大小为:8(或8乘以多继承时父类的个数);

c8} eB{%h2Tr Y"O0 51Testing软件测试网*o9G rr yV(dzM+u

  6、在考虑以上内容所占空间的大小时,还要注意编译器下的“补齐”padding的影响,即编译器会插入多余的字节补齐;51Testing软件测试网z4V`t6n9p JI

Oqq#Y#at0  7、类对象的大小=各非静态数据成员(包括父类的非静态数据成员但都不包括所有的成员函数)的总和+ vfptr指针(多继承下可能不止一个)+vbptr指针(多继承下可能不止一个)+编译器额外增加的字节。51Testing软件测试网P-b#|4\vY"[~

Q s[tXct0  示例一:含有普通继承51Testing软件测试网#[7X.t,Rw^a%H;` b

4^2~ qW4D9]3k0

h+[iw V2b%wO+N0

$z5DeS Z$A \z:\5d#K0class A  
!h!Q6Lg8@3O&R^0{  
RPB,~f{v~0}; 
51Testing软件测试网3Bfg*gT{%[A\t

(D5}FI G6Z(i0class B  
'e1e X}cX0{51Testing软件测试网 J0c!k lt!{7P&]
 char ch;  
4f6h#h0X s1A0dn-\l0 virtual void func0()  {  }
{7S!i6M1D3\N'?\0};

%T @z(z+_0

bX LTLYT0class C 
6lvxp*F-w`@0{
P9BD j6Ao`0 char ch1;51Testing软件测试网0?$^'U5kI
 char ch2;
yE#y!eH`B%rjvs0 virtual void func()  {  }  51Testing软件测试网&\Ms,J,K H
 virtual void func1()  {  }
1Y+Ao6A2qi;mh3a+O)O#f0};

z-B-\g M0 51Testing软件测试网Y D a s`1UI(H y!p

class D: public A, public C
5SH1h"V f3E0{   51Testing软件测试网9@5r;S,M'k$L W:d1f `(Y
 int d;   51Testing软件测试网%m}/XGj Bf/@B(y
 virtual void func()  {  } 51Testing软件测试网0Q0CACK/tV2{
 virtual void func1()  {  }51Testing软件测试网0pYvSE'C k2J \
};  

:d;];hO9up| L+]0

,GI+H1fB0class E: public B, public C
O-Z&Zgs$o0{  
h5[B R g'j9c0 int e;  
)pO+s'm y jL0 virtual void func0()  {  } 51Testing软件测试网*F/w S?C;u8P.iJ7t s
 virtual void func1()  {  }
h(ap BZ3k0};

*I1ZY"{@0c&d"B0

F8z.|4M+l#doc%L!|5P{0int main(void)
!j'e&I9PI4L be Z/^M1l0{51Testing软件测试网)b-cqYBu,?6Ln
 cout<<"A="<<sizeof(A)<<endl;    //result=1
M#L"v XD.l%M0 cout<<"B="<<sizeof(B)<<endl;    //result=8   
)j-rF%p6FsH @ Z0 cout<<"C="<<sizeof(C)<<endl;    //result=8
pCE0P'e\]f0 cout<<"D="<<sizeof(D)<<endl;    //result=1251Testing软件测试网"ob/K.|[)oYC
 cout<<"E="<<sizeof(E)<<endl;    //result=2051Testing软件测试网 \'z?,do]+D2{
 return 0;
S,L-C9W2H^0}
51Testing软件测试网t'c.vt9H-W{{

51Testing软件测试网X|e l6Kv+s

  前面三个A、B、C类的内存占用空间大小就不需要解释了,注意一下内存对齐就可以理解了。51Testing软件测试网'mi bJ a2i E

51Testing软件测试网8zdO?5H8I

  求sizeof(D)的时候,需要明白,首先VPTR指向的虚函数表中保存的是类D中的两个虚函数的地址,然后存放基类C中的两个数据成员ch1、ch2,注意内存对齐,然后存放数据成员d,这样4+4+4=12。51Testing软件测试网9Ly U!gT&T"e/e

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

F\S7GO M[7D/G0

.HXVQ n0  示例二:含有虚继承

@M~^*^?:D]0 51Testing软件测试网*lT}.Nq)h5_

s'er)JN:N3gD0

{}p/vo&O_V ]:l_ _0class CommonBase51Testing软件测试网*jN9S8Y;E#KK
{
[Fh G!s5Ij0 int co;51Testing软件测试网*Jt`o7Yj(C
};

Sr!x](X ] ?0

7q&UcyBO)CgR0class Base1: virtual public CommonBase
zv8U/t/]:e0{
]RN0x_,\3H?"c0public:51Testing软件测试网,rJLQ;gI|
 virtual void print1() {  }51Testing软件测试网"p)G6[T*K
 virtual void print2() {  }51Testing软件测试网'k;Ty/lNB
private:
L3H]%PIhe {w q0 int b1;
}w q8M jD-i*yx4u0};
51Testing软件测试网 k6D.TF(R+xM^)u5u3w

Xh'p RpLtE0class Base2: virtual public CommonBase51Testing软件测试网 {)j4_LQlc4J3^-O
{51Testing软件测试网 Ev`3N@6vJ ^qD
public:
^*pIqFZ`0 virtual void dump1() {  }51Testing软件测试网W6z|&D'_h Y3~WZ)n
 virtual void dump2() {  }
A'`(g%A#D*`![0private:51Testing软件测试网8|%`Q|T(x }O K
 int b2;51Testing软件测试网KM oEW
};

s7K?,iy~+P:y0 51Testing软件测试网#z R6pA.{e4?5`K

class Derived: public Base1, public Base2
(bOE sW"`/gp0{51Testing软件测试网`z?5oFo WO*SB
public:51Testing软件测试网{*f-`0esK C
 void print2() {  }
A;IukI F|8V0 void dump2() {  }
5jk c#PJN0private:51Testing软件测试网_ r+C"iq9j%@
 int d;51Testing软件测试网t:? B+r P!Ve!ML.|P4F
};

l+ozc*w0
51Testing软件测试网KIG6lX k_3k1r

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

9M8I"LkjlbL+X0 51Testing软件测试网%G.mY~h ^$l:| Q

3m n%x J0Z r;n;g3|%g"[0
class Derived size(32):51Testing软件测试网 \G ?p k2y"c['BW
     +---
J+~'R+x&dT!BV6c0     | +--- (base class Base1)
E2Yd R a ?0 | | {vfptr}51Testing软件测试网0Mk'@0R%H2|&it@&k'P
 | | {vbptr}51Testing软件测试网I Yyn|h~c|
 | | b151Testing软件测试网NeX/j#ujh7H+`[
     | +---
,lhJI'X{0     | +--- (base class Base2)
V]o6mAp%P0 | | {vfptr}
!n6QK!l;ti0 | | {vbptr}51Testing软件测试网b(t,Q-Q I-sa
 | | b251Testing软件测试网*U&V)A qK
    | +---51Testing软件测试网@1Q8Q.o:C
 | d
ib,F3Ek#J"qg6sw^fV0    +---
vo#eu*g4_v@F0    +--- (virtual base CommonBase)51Testing软件测试网 e"HHz^
 | co
TIX2?zQ0    +---
51Testing软件测试网7h]fy7Z X3o f

  示例3:

2@ y:@.B'L@2c0

e"m`JAk*TVPm0

1U]s9oA];p5b+Y,a,qS0

sI0]#VLD6vv0class A51Testing软件测试网$V1b e9a ygr
{51Testing软件测试网:g-shsK8Ni
public:51Testing软件测试网0s{M;v&U
 virtual void aa() {  }51Testing软件测试网l{k&h5Yli
 virtual void aa2() {  }
9J;w;`A,~|0private:51Testing软件测试网^e?(r3v8z J#[%u
 char ch[3];
hA:t'Q3v~i!PM?[0};
51Testing软件测试网+|[;Y6GUaZ_L

51Testing软件测试网5e/Jn%NNuxJ4n

class B: virtual public A
/NlbCpOe*zC0{51Testing软件测试网4dqO"Qq*L7N
public:
f9X a7a8{(PjhH7k0 virtual void bb() {  }51Testing软件测试网'd0[ X#_ED V)R?
 virtual void bb2() {  }51Testing软件测试网s2O#D)Y0D|j
};

$}-_1b(h#cY!v(?_0

f hB9C*V+g!}0int main(void)
V;K5]&r\'@"VkFY0{51Testing软件测试网&s8B*O g rh
 cout<<"A's size is "<<sizeof(A)<<endl;51Testing软件测试网3T(s!CXF\/v\
 cout<<"B's size is "<<sizeof(B)<<endl;
/B o5v5Ux7] zh5t,?`0 return 0;51Testing软件测试网:gC'{9hD7v2f
}

Ml}n I%|fwQ0
51Testing软件测试网5nd.[f2aa O,_D)T

  执行结果:A's size is 851Testing软件测试网7^![1r7ll0W

[Px-J4V5d[0  B's size is 16

r-a#EU\0 51Testing软件测试网?li2m#S/z]/_

  说明:对于虚继承,类B因为有自己的虚函数,所以它本身有一个虚指针,指向自己的虚表。另外,类B虚继承类A时,首先要通过加入一个虚指针来指向父类A,然后还要包含父类A的所有内容。因此是4+4+8=16。51Testing软件测试网&A8rs$Hs*P E#Hy.wc


TAG:

 

评分:0

我来说两句

Open Toolbar