【发布时间】:2016-05-16 14:44:03
【问题描述】:
class Base1 {
virtual void fun1() { cout << "Base1::fun1()" << endl; }
virtual void func1() { cout << "Base1::func1()" << endl; }
};
class Base2 {
virtual void fun1() { cout << "Base2::fun1()" << endl; }
virtual void func1() { cout << "Base2::func1()" << endl; }
};
class Test:public Base1,public Base2
{
public:
virtual void test(){cout<<"Test";}
};
typedef void(*Fun)(void);
int main()
{
Test objTest;
Fun pFun = NULL;
pFun = (Fun)*((int*)*(int*)((int*)&objTest+0)+0); pFun();
pFun = (Fun)*((int*)*(int*)((int*)&objTest+0)+1); pFun();
//The following isnt supposed to print Test::test() right?
pFun = (Fun)*((int*)*(int*)((int*)&objTest+0)+2); pFun();
pFun = (Fun)*((int*)*(int*)((int*)&objTest+1)+0); pFun();
pFun = (Fun)*((int*)*(int*)((int*)&objTest+1)+1); pFun();
//Isnt the following supposed to print Test:test() because the order of
construction object is Base1 followed by construction of Base2 followed by
construction of Test.
pFun = (Fun)*((int*)*(int*)((int*)&objTest+1)+2); pFun();
}
Test 对象的 sizeof 为 8 个字节。
所以从这个例子中可以明显看出,该对象由两个 4 字节的 _vptr 组成。由于继承顺序是public Base1,public Base2,这意味着对象应该按以下方式制作:
| _vptr to class Base1 vTable | -->this Base1 vtable should have 2 elements.
| _vptr to class Base2 vTable | -->this Base2 vtable should have 3 elements.
但从代码 sn-p 看来,对象是这样制作的:
| _vptr to class Base1 vTable | -->this Base1 vtable should have 3 elements.
| _vptr to class Base2 vTable | -->this Base2 vtable should have 2 elements.
第一个 vptr 指向一个包含 3 个函数指针的数组(第一个指向 Base1::fun1(),第二个指向 Base1::func1(),第三个指向 Test::test())。
派生对象由 Base+Derived 组成。这意味着第一个字节块是 Base 对象,其余的是 Derived。
如果是这样,那么在我们的 objTest 示例中,第二个 _vptr 应该指向三个函数指针(第一个指向 Base2::fun1()、Base2::func1() 和 Test::test())。但是我们看到第一个_vptr 指向Test::test() 的函数指针。
问题:
1.这种行为是编译器特有的吗?
2. 标准是否提到了这种行为?还是我的理解完全错误?
【问题讨论】:
-
所有这些都是未定义的行为,您使用
int表达式来读取未声明为int的对象 -
我不明白你的意思。我正在对 int 进行类型转换(这意味着我正在尝试将构成对象的那些字节读取为整数)。这有什么问题?
-
这是不允许的,因为有一种叫做严格别名规则的东西。要尝试检查任意内存,您需要使用
char或最好使用unsigned char。
标签: c++ multiple-inheritance vtable memory-layout vptr