C++ 对象模型学习记录(2)--- 第3章 data语义学
1. 关于sizeof的运行结果
#include <iostream>
//在GCC 中
using namespace std;
class X{};
class Y :public X{};
class Z : public X{};
class W :public Y,public Z{};
int main()
{
cout << sizeof(X) << endl;//1
cout << sizeof(Y) << endl;//1
cout << sizeof(Z) << endl;//1
cout << sizeof(W) << endl;//2
return 0;
}
而在vs 2010中是默认的编译器中
#include <iostream>
using namespace std;
class X{};
class Y :public X{};
class Z : public X{};
class W :public Y,public Z{};
int main()
{
cout << sizeof(X) << endl;//1
cout << sizeof(Y) << endl;//1
cout << sizeof(Z) << endl;//1
cout << sizeof(W) << endl;//1
return 0;
}
加了虚继承后,GCC和vs的竟然相同了,总的来说就是有了 virtual 继承,加了一个vptr指针和指向的是一个 要么是virtual base table,要么是offset
#include <iostream>
using namespace std;
class X{};
class Y :public virtual X{};
class Z : public virtual X{};
class W :public Y,public Z{};
int main()
{
cout << sizeof(X) << endl;//1
cout << sizeof(Y) << endl;;//4
cout << sizeof(Z) << endl;//4
cout << sizeof(W) << endl;//8
return 0;
}
2. 关于指向data member 数据成员的指针
#include <iostream>
#include <stdio.h>
using namespace std;
struct Base1{int val1; };
struct Base2{int val2; };
struct Derived : Base1,Base2 {};
//Derived2为了和Derived比较
struct Derived2 : Base1,Base2{int val3;};
void func1(int Derived::*dmp,Derived *pd)
{
//期望传进来的是一个"指向 derived class 的member "的指针
//如果传进来的是“指向base class 的member”的指针,
//结果如何?
cout << pd->*dmp << endl;
}
void func2(Derived *pd)
{
//bmp将成为1
int Base2::* bmp = &Base2::val2;//Base2::* 型的变量
cout << bmp << endl;
printf("~~~~~~~~~~~~~~~~~~~%d\n",bmp);
func1(bmp,pd);
//这里必须由编译器内部转换
// func1(,pd);
}
int main()
{
Base1 base1;
base1.val1 = 1;
Base2 base2;
base2.val2 = 2;
Derived d;
Derived *p = &d;
func2(p);
cout << "-------------------" << endl;
//以下结果都是0
printf("&Base1::val1 = %p\n",&Base1::val1);
printf("&Base2::val2 = %p\n",&Base2::val2);
printf("&Derived::val1 = %p\n",&Derived::val1);
printf("&Devrived::val2 = %p\n",&Derived::val2);
cout << &Base1::val1 << endl;
cout << &Base2::val2 << endl;
cout << &Derived::val1 << endl;
cout << &Derived::val2 << endl;
cout << "--------------" << endl;
printf("&Derived2::val1 = %p\n",&Derived2::val1);
printf("&Devrived2::val2 = %p\n",&Derived2::val2);
printf("&Derived2::val = %p\n", &Derived2::val3 );
cout << &Derived2::val1 << endl;
cout << &Derived2::val2 << endl;
cout << &Derived2::val3 << endl;
return 0;
}
运行结果如下:GCC和VC下都是同样的结果
可以看出的是 在c++中cout 和printf 输出的结果竟然还是不一样的 == ,应该是 C++重载了 <<运算符,使<<能够适应各种输出的原因吧
int Base2::* bmp = &Base2::val2;//Base2::* 型的变量
cout << bmp << endl;
通过 cout 可以看出这里输出的就是1,但是 在GCC下 不能转化为 int型的,所以才有了调用 func1(bmp,pd); 并在函数中 cout << pd->*dmp << endl; 时得到了 一个随机数
对于C++对象模型中所说的 &Base1::val1 中val 指的是 val在类的对象中的偏移量问题,只能通过printf("&Base1::val1 = %p\n",&Base1::val1);看到,cout 方式可能还是因为重载的缘故吧:所有的输出都是1(不知道原因,可能不是偏移量了吧)
printf("&Devrived::val2 = %p\n",&Derived::val2); 对于&Derived::val2实际的偏移量应该是4,可能由于编译器的优化,输出为0了。。(怎么优化的? 想不明白)
书中以 printf("&Derived2::val = %p\n", &Derived2::val3 ); 打印出了 val3的偏移量为8,可以看出
3. 那个point2d,3d问题
#include <iostream>
#include <stdio.h>
using namespace std;
class Point3d
{
public:
virtual ~Point3d();
Point3d(float a,float b,float c)
{
x = a;
y = b;
z = c;
// origin(x,y,z);
}
static Point3d origin;
static void f()
{
//error: request for member 'x' in 'Point3d::origin',
//which is of non-class type 'Point3d()'
//printf("&origin.x = %p\n",&(origin.x));
//printf("&origin.y = %p\n",&origin.y);
//printf("&origin.z = %p\n",&origin.z);
// printf("&origin = %p\n",&origin);
}
float x,y,z;
};
int main()
{
float f = 1.0;
cout << sizeof(f) << endl;
cout << sizeof(float) << endl;
cout << sizeof(double) << endl;
printf("&Point3d::x = %p\n",&Point3d::x);//计算的是偏移量 4
printf("&Point3d::y = %p\n",&Point3d::y);//4 ,结果是8
printf("&Point3d::z = %p\n",&Point3d::z);//4 结果是C(12)
cout << "&Point3d::x = " << &Point3d::x << endl;
cout << "&Point3d::y = " << &Point3d::y << endl;
cout << "&Point3d::z = " << &Point3d::z << endl;
//undefined reference to `Point3d::origin'
// printf("&origin.x = %p\n",&(Point3d::origin.x));
// printf("&origin.y = %p\n",&Point3d::origin.y);
// printf("&origin.z = %p\n",&Point3d::origin.z);
Point3d p();
//Point3d::f();
return 0;
}
木有打印出来 origin.x ,错误是
(1) //undefined reference to `Point3d::origin' ,
(2)//error: request for member 'x' in 'Point3d::origin',
//which is of non-class type 'Point3d()'
将 virtual ~Point3d(); 去掉虚函数~,变为 Point3d()并完成初始化后:Point3d Point3d::origin(1,1,1);
#include <iostream>
#include <stdio.h>
using namespace std;
class Point3d
{
public:
~Point3d(){};
Point3d(float a,float b,float c)
{
x = a;
y = b;
z = c;
}
static Point3d origin;
float x,y,z;
};
Point3d Point3d::origin(1,1,1);
int main()
{
float f = 1.0;
cout << sizeof(f) << endl;
cout << sizeof(float) << endl;
cout << sizeof(double) << endl;
printf("&Point3d::x = %p\n",&Point3d::x);
printf("&Point3d::y = %p\n",&Point3d::y);
printf("&Point3d::z = %p\n",&Point3d::z);
cout << "&Point3d::x = " << &Point3d::x << endl;
cout << "&Point3d::y = " << &Point3d::y << endl;
cout << "&Point3d::z = " << &Point3d::z << endl;
//undefined reference to `Point3d::origin'
printf("&origin.x = %p\n",&(Point3d::origin.x));
printf("&origin.y = %p\n",&Point3d::origin.y);
printf("&origin.z = %p\n",&Point3d::origin.z);
//Point3d::f();
return 0;
}
结果如下:
对比与 两个图中的 &Point3d::x 值得出结论:
在GCC编译器中,如果加了 virtual ,它的对象布局中应该是 vptr在 数据成员的上面
而不是像 c++对象模型 cfont 编译器中在数据成员下面
一个不会敲代码的程序员