so true

心怀未来,开创未来!
随笔 - 160, 文章 - 0, 评论 - 40, 引用 - 0
数据加载中……

c++内存对象布局

收藏陈皓的几篇博文:
http://haoel.blog.51cto.com/313033/124567
http://haoel.blog.51cto.com/313033/124561
http://haoel.blog.51cto.com/313033/124595

看完上面的文章,应该可以回答一个问题:指针被强制类型转化之后,指针的值会改变吗?
答案:有时候是会的。haoel把继承分为5类,我再把它们作个标记:
没有虚继承:单一继承(1), 非重复多重继承(2), 重复多重继承(3);
有虚继承:单一继承(4),重复多重继承(5)。
我先区别两个概念“类的内存布局(由此可以计算出类的大小)”和“类本身的内存布局(由此可以计算出类本身的大小)”:
sizeof(类)= sizeof(类本身) + sizeof(所有父类)。
而类本身的内存布局由两部分构成:vptr + 成员变量, 整个类的内存布局是把类本身和所有父类的内存布局拼接在一起的,注意:对于类型(1),整个类只有一个vptr,因此父类的内存布局只有成员变量了。

拼接的规则是:先父类后子类,但特例是虚拟继承,在虚拟继承时,会变成“先子类后父类”,因为虚拟继承的目的是:认为父类有common的东西,大家共享之。

因此,vptr不一定只能出现在类内存布局的始端,准确的说: 应该是出现在各个类本身的内存布局的始端。
当发生类型转化时,比如要从Derived*转化到Base*,转化后的结果会是指向“Base这个父类自身的内存布局的始端”,一旦这个始端和“Derived类的内存布局始端“不一致,那么
就发生了指针类型转化后指针值的改变。
下面是一个例子:
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <set>

using namespace std;

class A {
public:
    virtual ~A() {};
    int iA;
};

class A1 {
public:
    virtual ~A1() {};
    int iA1;
};

class B: public A {
public:
    virtual ~B() {};
    int iB;
};

class C: virtual public A {
public:
    virtual ~C() {};
    int iC;
};

class D: public A, public A1 {
public:
    virtual ~D() {};
    int iD;
};

int main(int argc, char* argv[]) {
    A* pa = new B();
    cout << "B size:" << sizeof(B) << endl;
    cout << "A addr:" << pa << endl;
    cout << "B addr ():" << (B*)pa << endl;
    cout << "B addr dynamic_cast:" << dynamic_cast<B*>(pa) << endl;

    cout << "-------------------------------" << endl;

    A* pa2 = new C();
    cout << "C size:" << sizeof(C) << endl;
    cout << "A addr:" << pa2 << endl;
    //cout << "C addr ():" << (C*)pa2 << endl; //compile error
    cout << "C addr dynamic_cast:" << dynamic_cast<C*>(pa2) << endl;

    cout << "-------------------------------" << endl;

    C* pc = dynamic_cast<C*>(pa2);
    cout << "C addr dynamic_cast:" << pc << endl;
    cout << "A addr ():" << (A*)pc << endl;
    cout << "A addr dynamic_cast:" << dynamic_cast<A*>(pc) << endl;

    cout << "-------------------------------" << endl;

    D* pd = new D();
    cout << "D size:" << sizeof(D) << endl;
    cout << "D addr:" << pd << endl;
    cout << "A addr ():" << (A*)pd << endl;
    cout << "A addr dynamic_cast:" << dynamic_cast<A*>(pd) << endl;
    cout << "A1 addr dynamic_cast:" << dynamic_cast<A1*>(pd) << endl;
    return 0;
}

结果:
B size:16
A addr:0x8a96010
B addr ():0x8a96010
B addr dynamic_cast:0x8a96010
-------------------------------
C size:32
A addr:0x8a96040
C addr dynamic_cast:0x8a96030
-------------------------------
C addr dynamic_cast:0x8a96030
A addr ():0x8a96040
A addr dynamic_cast:0x8a96040
-------------------------------
D size:32
D addr:0x8a96060
A addr ():0x8a96060
A addr dynamic_cast:0x8a96060
A1 addr dynamic_cast:0x8a96070

下面还有篇对haoel的介绍,也一并收藏了:
http://news.csdn.net/n/20070706/106194.html

posted on 2011-04-24 12:52 so true 阅读(1949) 评论(0)  编辑  收藏 所属分类: C&C++


只有注册用户登录后才能发表评论。


网站导航: