2012.11.19

1.printf

printf("%4d", 12),打印结果为  12(空格空格12),4的含义是如果打印的数字不足4个,则用空格补齐。

printf("%04d", 12),打印结果为0012,04的含义是如果打印数字不足4个,则用0补齐。


2.关于虚函数表指针设置的时机

在一般情况下,每个类在构造和析构的时候,在运行函数体之前都需要首先将自己的vptr指向为当前ctor或者dtor所在的类的那个vtbl。如果ctor和dtor里面没有运行虚函数,这样的设置显然造成了效率的浪费,我估计这里应该有优化的,即哪一层ctor或者dtor调了虚函数,则那一层的ctor和dtor里面设置vptr,另外能够实例化的那一层类的ctor也必须设置vptr,否则实例化出来的对象的vptr就不对了,从而虚函数机制也就会出错。


3.关于多重继承(无虚继承的情况下)

struct A
{
    int a;
    virtual void FA();
}

struct B : public A
{
    int B;
}

struct C:
{
    int c;
    virtual void FC();
}

struct D : public B, public C
{
    int d;
}

A的内存

int a;

vptr_A;


B的内存

int a;

vptr_A;

int b;


C的内存

int c;

vptr_C;


D的内存

int a;

vptr_A;

int b;

int c;

vptr_C;

可以看出,在无虚继承的情况下,多重继承其实就是把被继承的类的内存顺序摆放就行了,这里唯一需要注意的是,指针的转换,对于单继承,继承链上的类的指针转换不需要做任何额外的东西,但多继承不同。

D* pd = new D;

把pd赋值给第一继承链上的类的指针,即A*和B*,直接赋值就可以了,但赋给第二继承链上的类的指针时,即C*,要把pd加上sizeof(B),如果不这样处理,依然直接赋值,那么在处理单继承C的类的指针时,就没有办法了。

struct C2 : public C
{
    int c2;
}

C2的内存

int c;

vptr_C;

int c2;


C* pc1 = new D;

C* pc2 = new C2;

如果在多重继承的时候不做上面的处理,那么pc1所指对象的正确地vptr在pc1下面16个字节处,pc2所指对象的正确的vptr在pc2下面的4个字节处,因为pc1和pc2都是C*,编译器在对他们进行虚函数调用时,不可能说一个偏移16个字节取vptr,一个偏移4字节取vptr,这个偏移值必须得的固定的,这就是多重继承时,指针转换到非第一继承链上的类时候,必须要做额外工作的原因。


4.关于虚继承。

这个比较麻烦,而且实现方法,现在也有很多种,我就不细说实现方法了,只说它的难点在哪,以及解决思路。

在菱形继承的情况下,最终派生类只能有一份顶端基类的实例,只有一份很简单,那就只有一份呗,难点在于上面说过的在多条继承链的指针切换时,通过每一种指针都能够指到那唯一的一份实例,一种比较质朴的思路就是在vptr下面加一个vbcp指向那一份实例,这种思路还有一些变种,我就不细说了。

另外《深入C++对象模型》里面还说道,虚继承最好的使用地方是,菱形继承的那个顶端类是一个没有数据的纯接口,但以我现在知识推到,这种情况不应该用虚继承,用了虚继承不止增加了间接性还增加了空间消耗,但CEGUI的D3D9TextureTarget就是用的虚继承,应该是我理解还不到位。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值