一、没有虚函数,没有继承的类内存结构:
1.如下定义一个类:
class A
{
public:
void seta(int x) {a = x;};
void setb(int x) {b = x;};
int sum() {return a+b;};
private:
int a;
int b;
};
A test;
当实例化以后,实际上实例test的内存结构只有两个变量成员a和b;
而类的函数在操作时,其输入参数比实际看到的多一个,即寄存器ecx,ecx指向实例地址。比如在例子中,函数seta的代码是如下的:
mov eax, [esp+arg_0]
mov [ecx], eax
retn 4
也就是说,A.seta的实际上可以这样写: void seta(&A,int x);
2.在类中,变量是按定义的顺序组织的。不管这些变量是public,privated还是protected。
二、没有虚函数,有继承的类内存结构:
class A
{
public:
void seta(int x){a = x;};
privated:
int a;
};
class B:class A
{
public:
void setb(int x){b = x;};
privated:
int b;
};
在这样的实例中,先分配父类变量,再分配子类变量。
如果是多重继承的话,则按顺序分配父类的变量。
三、有虚函数,没有继承的类内存结构:
若果类中含有虚函数时,类对象的内存分配有不一样的地方。如:
class A
{
public:
virtual init(int x,int y){a = x;b = y;};
virtual init(){a = 0;b=0;};
int sum();
priviate:
int a,b;
}
此时,在类实例内存中,首先是虚函数表指针,然后才分配变量。
vc6编译器下,当虚函数个数为偶数时,已0xffffffff结束。为奇数时,先填充0,再已0xffffffff结束。
四、有虚函数,单继承的类内存结构:
单继承关系分为虚函数覆盖和不覆盖两种,当不覆盖时,虚函数表先是父类的虚函数表,然后是子类的虚函数表,当覆盖时,同样排序,但父类的被覆盖虚函数地址为子类的相应的虚函数的地址。
变量的分配和上面的相同。
五、有虚函数,多继承的类内存结构:
class C
{
public:
virtual C1(){return 1;};
virtual C2(){return 2;};
setc(int x){c = x;};
private:
int c;
};
class B
{
public:
virtual B1(){d1=1;};
virtual B2(){d2=2;};
private:
int d1;
int d2;
};
class A
{
public:
int sum(){return a1+a2;};
virtual A1(int x,int y){a1 = x;a2 = y;};
virtual A2(){a3=0;};
virtual A3(int x){a3 = x;};
virtual A4(){a1*a2*a3;};
private:
int a1;
int a2;
int a3;
};
class D:public A,public B,public C
{
public:
virtual D1(int x,int y){d1=x+10;d2=y+10;d3=d1*5;d4=d2*7;};
virtual D2(){return 8;};
private:
int d1,d2,d3,d4;
};
此时,类D 的实例的内存分配应该如下:
A的虚函数表指针,紧跟这个虚函数表的是D的虚函数地址。
A的变量分配
B的虚函数表指针
B的变量分配
C的虚函数表指针
C的变量分配
D的变量分配
如果有虚函数覆盖,则和上面描述相同,用D的虚函数地址覆盖相应的父类的虚函数表中虚函数的地址。
阅读(2599) | 评论(0) | 转发(0) |