收藏陈皓的几篇博文:
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