深入探索C++对象模型读书笔记 (三)

Posted on 2010-03-07 16:39 rikisand 阅读(279) 评论(0)  编辑 收藏 引用 所属分类: C/C++

DATA 语义学

这段代码输出什么?

#include <iostream>
using namespace std;
class A{ public:A(){ac='s';}private:char ac;};
class B:virtual public A{public:B(){a='e';}char a; };
class C:virtual public A{ };
class D:public  B,public  C
{
public:
    D():A(),B(),C(){b=13;}
    int b;
};
int main(){
    D d;
    cout<<"sizeof(A)="<<sizeof(A)<<endl;
    cout<<"sizeof(B)="<<sizeof(B)<<endl;
    cout<<"sizeof(C)="<<sizeof(C)<<endl;
    cout<<"sizeof(D)="<<sizeof(D)<<endl;
    cout<<endl;
    cout<<"address of A's subobject in d"<<(A*)&d<<endl;
    cout<<"address of B's subobject in d"<<(B*)&d<<endl;
    cout<<"address of C's subobject in d"<<(C*)&d<<endl;
    cout<<"address of D's subobject in d"<<(D*)&d<<endl;
    cout<<endl;
    int* p = (int*)(*((int*)&d));
    cout<<"address of b's virtual base table="<<p<<endl;
    cout<<"first member in b's virtual base table="<<*p<<endl;
    cout<<"second member in b's virtual base table="<<*(p+1)<<endl;
    cout<<"third member in b's virtual base table="<<*(p+2)<<endl;
    cout<<endl; 
    p= (int*)*((int*)((C*)&d));
    cout<<"address of c's virtual base class table= "<<p<<endl;
    cout<<"first member in c's virtual base table="<< *p<<endl;
    cout<<"second member in c's virtual base table="<<*(p+1)<<endl;
    cout<<"third member in c's virtual base table="<<*(p+2)<<endl;
    char *pchar= (char*)(&d)+4; //char型加4   注意A中的ac其实是私有变量,B不应该可以访问到的,实际上通过强制转换可以非法触及她-。-
    cout<<*pchar<<endl;
    cout<<*(pchar+12)<<endl;
    B b;
    int *pint =(int*)(&b)+1; //int型+1 
    cout<<*((char*)(pint))<<endl;
    pint = (int*)(&d)+3;
    cout<<*(pint)<<endl;
}

 

结果是:

sizeof(A)=1
sizeof(B)=9
sizeof(C)=5
sizeof(D)=17

address of A's subobject in d0012FF74
address of B's subobject in d0012FF64
address of C's subobject in d0012FF6C
address of D's subobject in d0012FF64

address of b's virtual base table=00403350
first member in b's virtual base table=0
second member in b's virtual base table=16
third member in b's virtual base table=0

address of c's virtual base class table= 00403358
first member in c's virtual base table=0
second member in c's virtual base table=8
third member in c's virtual base table=0
e
s
e
13

 

1.语言本身造成的负担:如virtual baseclass

2.对齐造成的负担(对齐会单独开题讨论)

3.编译器优化处理 A虽然是空的 but 为了让A的两个object在内存中得到不同的地址,编译器给他加上了一个byte,但是B和C都没有这一个byte呢?这是编译器做了优化,允许省掉这一个byte

看上面的代码”:

环境是vs2008 对齐设置为4字节

A的大小为1 因为有一个char 没有对齐因为不是结构型对象,如果A没有这个char大小依然是1的

B的大小为9 首先开始是它的virtual base class ptr,4个字节的指针,然后是他自己的member 1个char 此时为了保证其对象完整性编译器对齐到4字节处也就是在第九个字节内放入基类的member

这样如果我们把A=B B赋给A,传输可以从整4字节开始割出A即可

C的大小是5 没什么好解释

D的大小是17首先是B的8字节(4字节vbptr+1字节char member+3字节对齐)然后是C的4字节vbptr,然后是自己的member4字节最后是1字节的base class member,可以看到B和C的base class table中的项都是自己位置与这个member的offset 值

 

不同编译器可能结果不同的,因为c++ standard 并没有强制规定 base class subobjects的顺序等

 

data member 是程序执行过程中的某种状态:

static data member 是整个class 的状态

non-static data member 是个别class-object 的状态

c++对象尽量以空间优化和存取速度的考虑来表现non-static members ,并且和c的struct 数据配置的兼容性。

static data member 放在程序的一个global data segment 中,不会影响个别的class-object 大小

,在class没有object 时已经存在,但是template中有些不同

 

-----DATA member 的绑定

始终把nested type 声明 放在class 起始处,argument list 中的名称会在第一次遇到时候被适当的决议完成,因此extern 和nested type names 之间的非直觉绑定操作还是会发生。

---- DATA 的存取

Point3d origin,*pt=&origin;

origin.x = 0.0; 和 pt->x=0.0 ; 有什么区别么??

如果x是静态data member 则完全没有区别 因为他们都在data segment 中和object无关

~nonstatic data member---------

如果point3d不包含虚拟继承那么没有差异

否则我们不能确定pt中必然指向哪一种因此不能在编译器确定offset需要一些运行时候的计算抉择,而origin则不同一定是某一个类型的所以没有问题

多继承或者单继承都不会带来访问上的影响,因为他们都可以向c的结构体那样在编译时期确定各个member的offset。即使是多继承pt指向第二个baseclass的data,由于member的位置在编译时期就已经固定了,因此存取member只是一个offset运算,像单一继承那样简单,不管是指针,reference或者object都一样

只有virtual base class 会带来一些损耗,因为他使得对象模型变得复杂了

如果我们在一个类中加入了virtual func 会发生什么~~~

1. 会产生一个virtual table,存放每一个virtual func地址以及rtti支持的type_info

2.class object 内都加入一个vptr,提供执行期的链接

3.加强ctor 设定vpr初值

4.加强dtor 消除vptr 从dirived class 到 base class

 

虚拟继承:

他必须支持某种形式的“shared subobject”继承

那么一个object会分成一个不变局部和一个共享局部的数据,共享局部就是virtual base class subobject,他的位置会因为每次派生操作发生变化(例如一个virtual base class subobject的位置在不同级别的继承体系中的位置是不确定的,不像多继承单继承那样有固定的offset),所以他只能间接存取,因此产生了效率缺损.(间接是指的是他只能首先读出他的指针,然后根据指针的内容取到他)

所以在虚拟继承基类中最好不要有data member

-------指向DATAmember 的指针

#include <iostream>
using namespace std;

class  A
{
public:

    int a;
};
int main(){
    int  A::* p=&A::a;
    cout<<p<<endl;
}

输出 1

因为为了防止&A::a和 int A::*a = 0;一样把他加了1。

 

虚拟继承带来的主要冲击是,妨碍了优化的有效性,因为每一层虚拟继承都带来了一个额外层次的间接性,在编译器中存取 类似point::x的操作pb.*bx

会被转化为 &pb->vbcPoint+bx

而不是转换成 &pB +bx

额外的间接性会降低“把所有操作都搬移到缓存器中执行”优化能力,也就是降低了局部性~

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理