虚继承,派生类重写基类虚函数,派生类大小的问题,具体看代码
#ifExample_1#defineUseVirtualBase1classA{public:A(){cout<<"createA!"<<endl;};virtual~...
#if Example_1
#define UseVirtualBase 1
class A
{
public:
A()
{
cout << "create A!" << endl;
};
virtual ~A()
{
cout << "delete A!" << endl;
};
virtual void test()
{
cout << "test from A!" << endl;
}
public:
int a; // 4bytes
private:
char *p;// 内存对齐,补充为4bytes
/*
总共4+4+4=12bytes
*/
};
#if UseVirtualBase
class B : virtual public A
#else
class B : protected A
#endif
{
public:
B()
{
cout << "create B!" << endl;
};
~B()
{
cout << "delete B!" << endl;
};
/*
如果是虚继承,则此处表明子类有一个自己的虚函数表,
即要维护一个独立虚指针vfptr_B;
如果不是虚继承,则子类和父类共用一个虚函数表,共用一个虚指针
*/
virtual void test2()
{
}
virtual void test()
{
cout << "test from B!" << endl;
}
private:
static int st;
int d; // 4bytes
char *p; // 4bytes
char c; // 内存对齐,补充为4bytes
/*
(4+4+4)+12=24bytes
(4+4+4)+4+4+12=32bytes
*/
};
#endif
类A的大小是12,这没有问题
类B的大小输出是36,
我能理解的是:
1.类B自己的非静态成员变量,(4+4+4)
2.指向虚基类表的一个指针,4
3.指向自身虚函数表的一个指针,4
加起来是32,
试了一下,剩下的4Bytes,好像是因为重写了虚基类的虚函数,但是不明白其中的原因,跪求高手指点一下,谢谢了!!! 展开
#define UseVirtualBase 1
class A
{
public:
A()
{
cout << "create A!" << endl;
};
virtual ~A()
{
cout << "delete A!" << endl;
};
virtual void test()
{
cout << "test from A!" << endl;
}
public:
int a; // 4bytes
private:
char *p;// 内存对齐,补充为4bytes
/*
总共4+4+4=12bytes
*/
};
#if UseVirtualBase
class B : virtual public A
#else
class B : protected A
#endif
{
public:
B()
{
cout << "create B!" << endl;
};
~B()
{
cout << "delete B!" << endl;
};
/*
如果是虚继承,则此处表明子类有一个自己的虚函数表,
即要维护一个独立虚指针vfptr_B;
如果不是虚继承,则子类和父类共用一个虚函数表,共用一个虚指针
*/
virtual void test2()
{
}
virtual void test()
{
cout << "test from B!" << endl;
}
private:
static int st;
int d; // 4bytes
char *p; // 4bytes
char c; // 内存对齐,补充为4bytes
/*
(4+4+4)+12=24bytes
(4+4+4)+4+4+12=32bytes
*/
};
#endif
类A的大小是12,这没有问题
类B的大小输出是36,
我能理解的是:
1.类B自己的非静态成员变量,(4+4+4)
2.指向虚基类表的一个指针,4
3.指向自身虚函数表的一个指针,4
加起来是32,
试了一下,剩下的4Bytes,好像是因为重写了虚基类的虚函数,但是不明白其中的原因,跪求高手指点一下,谢谢了!!! 展开
2个回答
展开全部
“如果是虚继承,则此处表明子类有一个自己的虚函数表”
我觉得你理解有点点错误,就算是虚继承,虚函数所在的表也只是同一份,不同的是,父类和子类都保存了一个指向该虚函数表的指针(而普通的继承只有一个指向虚函数表的指针)。
之所以会多于4Bytes 应该是B类中test2()这个虚函数父类中没有,又由于是虚继承的特殊性,所以在B类中test()和test2()不在同一个虚函数表中,B类另外用了一个指针保存test2()所在的虚函数表地址,所以这里B类才会有两个虚函数表,才会多出4Bytes,这4Bytes是另外一个虚函数表的地址,我是这么理解的!也实践证明过test2()并不在test()所在的虚表中,如有不同意见,或觉得有误,请提出,共同学习!
我觉得你理解有点点错误,就算是虚继承,虚函数所在的表也只是同一份,不同的是,父类和子类都保存了一个指向该虚函数表的指针(而普通的继承只有一个指向虚函数表的指针)。
之所以会多于4Bytes 应该是B类中test2()这个虚函数父类中没有,又由于是虚继承的特殊性,所以在B类中test()和test2()不在同一个虚函数表中,B类另外用了一个指针保存test2()所在的虚函数表地址,所以这里B类才会有两个虚函数表,才会多出4Bytes,这4Bytes是另外一个虚函数表的地址,我是这么理解的!也实践证明过test2()并不在test()所在的虚表中,如有不同意见,或觉得有误,请提出,共同学习!
追问
额, 谢谢w3931242wwj的指教.
呵呵,理解这些,一直不知道怎么查看这些虚函数表,虚基类表,只能在网上东找西找!
能教教我你是咋做的吗??
追答
想获得虚函数表地址可以这样做,由于虚函数表的指针被隐藏了,不能直接得到,但是可以暴力强行获得,写一个没有任何数据的类,申明一个虚函数
class A
{
virtual void test(){}
}
这样,类A中只有一个4字节数据,就是V-Table(虚函数表)的指针
A a;
&a --->类a的地址
*(&a) ---->获得a中第一个数据,也就直接获得V-Tabe的指针
*(*(&a)) ---->获得虚函数表地址
比如,要证明该类所有实例都用的是同一张V-Table可以这样做:
创建两个实例
A a1;
A a2;
cout<<&(*(int*)(&a1))<<endl;
cout<<&(*(int*)(&a2))<<endl;
// 分别输出a1和a2 中 V-Talbe的指针的地址,两个指针肯定不同
cout<<&(*(int*)*(int*)(&a1))<<endl;
cout<<&(*(int*)*(int*)(&a2))<<endl;
//这里 输出V-Table地址,因为两个指针指向同一地址,肯定是一样的
看着有些晦涩.....
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询