分享
 
 
 

深度探索C++对象模型(8)

王朝c/c++·作者佚名  2006-01-06
窄屏简体版  字體: |||超大  

作者: 雷神

书的第四章后半部分详细的讲解内联函数,由于比较容易理解,雷神做一个简单总结便过去吧。

内联函数和其他的函数相比是一种效率很高的函数,未优化的情况下效率可以提高25%,优化以后简直是数量级的变化,书上的给出的数据是0.08比4.43。简直没法比了。内联函数对于封装提供了一种必要的支持,可以有效的存去类中的非共有数据成员,同时可以替代#define(前置处理宏)。但是它也有缺点,程序会随着调用内联函数次数的增多,而产生大量的扩展码。

在内联函数的扩展时每一个形式参数被对应的实参取代,因此会有副作用。通常需要引入临时对象解决多次对实际参数求值的操作产生的副作用。

第五章的开始给出了一个不恰当的抽象类的声明:

class Abstract_base

{

public:

virtual ~Abstract_base()=0;//纯虚析构函数

virtual void interface() const=0; //纯虚函数

virtual const char* mumble() const{return _mumble;}

protected:

char *_mumble;

};

这是一个不能产生实体的抽象类,因为它有纯虚函数。为什么说它存在不合适的地方呢?以下逐一进行说明。

1、 它没有一个明确的构造函数,因为没有构造函数来初始化数据成员则它的派生类无法决定数据成员的初值。类的成员数据应该在构造函数或成员函数中被指定初值,否则将破坏封装性质。

2、 每一个派生类的析构函数会被编译器进行扩展以静态调用方式调用其上层基类的析构,哪怕是纯虚函数。但是编译器并不能在链接时找到纯虚的析构函数,然后合成一个必要的函数实体,因此最好不要把虚的析构函数声明成纯虚的。

3、 除非必要,不要把所有的成员函数都声明为虚函数。这不是一个好设计观念。

4、 除非必要,不要使用const声明函数,因为很多派生的实体需要修改数据成员。

有了以上的观点上面的抽象类应该改为下面这种样子:

class Abstract_base

{

public:

virtual ~Absteact_base(); //不在是纯虚

virtual void interface()=0; //不在是const

const char * mumble() const{return _mumble;} //不在是虚函数

protected:

Abstract_base(char *pc=0); //增加了唯一参数的构造

Char *_mumble;

};

下一个问题,对象的构造。构造一个对象出来很简单,这是我们在编程时经常要做的事情。我理解书上的意思是为我们分析了各种不同的类,例如一个没有Copy constructor,Copy operator的类,或者有私有变量但是没有定义虚函数的类等等,当他们构造对象时也有多种情况,global,local,还有在new时,编译器都做了什么,内存的分配情况如何。搞清楚它们也很有意思。另外这好象是前面几章学到的东西的一个进一步的研究。我们找出最复杂的虚拟继承来进行一下研究。当一个类对象被构造时,实际上这个类的构造函数被调用,不论是我们自己写的,还是由编译器为我们合成的。并且编译器会背着我们做很多的扩充工作,将记录在成员初始化列表中的数据成员的初始化工作放进构造函数,如果一个数据成员没有在成员初始化列表中出现,则会调用默认的构造函数,这个类的所有基类的构造都会被调用,以基类的声明顺序。所有的虚拟基类的构造也会被调用。还要为virtual table pointers设定初始值,指向适当的virtual tables。好家伙,编译器还真累。好象说的不是很清楚,抄一段书上的代码。

已知一个类的层次结构和派生关系如下图:

见书上P211。

这是程序员给出的PVertex的构造函数:

PVertex::PVertex(float x,float y,float z):_next(0),Vertex3d(x,y,z),Point(x,y)

{

if(spyOn)

cerr<<”within PVertex::PVertex()”<<”size:”<<size()<<endl;

}

它可能被扩展成为:

//C++伪码

// PVertex构造函数的扩展结果

PVertex *

PVertex::PVertex(PVertex * this,bool most_derived,float x,float y,float z)

{

//条件式的调用虚基类的构造函数

if(_most_derived!=false)

this->Point::Point(x,y);

//无条件的调用上层基类的构造函数

this->Vertex3d::Vertex3d(x,y,z);

//将相关的vptr初始化

this->_vptr_PVertex=_vtbl_PVertex;

this->_vptr_Point_PVertex=_vtbl_Point_PVertex;

//原来构造函数中的代码

if(spyOn)

cerr<<”within PVertex::PVertex()”<<”size:”

//经虚拟机制调用

<<(*this->_vptr_PVertex[3].faddr )(this)<<endl;

//返回被构造的对象

return this;

}

通过上面的代码我们可以比较清晰的了解在有多重继承+虚拟继承的时候构造一个对象时,编译会将构造函数扩充成一个什么样子。以及扩充的顺序。知道了这个相对于无继承,或者不是虚拟继承时对象的构造应该也可以理解了。与构造对象相对应的是析构。但是构造函数和析构函数和new和delete不同,他们并非必须成对的出现。决定是否为一个类写构造函数或者析构函数,是取决于这个类对象的生命在哪里结束(或开始)。需要什么操作才能保证对象的完整。象构造函数一样析构函数的最佳实现策略是维护两份destructor实体。一个complete object实体,总是设定好vptrs,并调用虚拟基类的析构函数。一个base class subobject实体。除非在析构函数中调用一个虚函数,否则绝不会调用虚拟基类的析构函数,并设定vptrs。

一个对象生命结束于析构函数开始执行的时候。它的扩展形式和构造函数的扩展顺序相反。

看到这章我又有点晕了。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有