扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
现有如下代码:
创新互联是一家专注于成都网站设计、网站制作与策划设计,东源网站建设哪家好?创新互联做网站,专注于网站建设10余年,网设计领域的专业建站公司;建站业务涵盖:东源等地区。东源做网站价格咨询:18982081108
class Abstract_base
{
public:
virtual ~Abstract_base() = 0;
virtual void interface() const = 0;
virtual const char* mumble() const { return _mumble; }
protected:
char* _mumble;
}
以上抽象基类声明有几个问题:
//合理的声明
class Abstract_base
{
public:
virtual ~Abstract_base();
virtual void interface() = 0;
const char* mumble() const { return _mumble; }
protected:
Abstract_base( char* pc = 0 );
char* _mumble;
}
现有如下片段:
typedef struct
{
float x, y, z;
}Point;
Point global;
Point foobar()
{
Point local;
Point* heap = new Point;
*heap = local;
delete heap;
return local;
}
对于Point这样的声明,在c++会被贴上Plain OI' Data标签。编译器并不会为其声明default constrcutor、destructor、copy constructor、copy assignment operator
对于 Point global; 这样的定义,在c++中members并没有被定义或调用,行为和c如出一辙。编译器并不会调用constructor和destructor。除非在c中,global被视作临时性定义
临时性定义:因为没有显示初始化操作,一个临时性定义可以在程序多次发生,但编译器最终会将这些实例链接折叠起来,只留下一个实例,放在data segment中"保留给未初始化的global object使用的"空间
但在c++中并不支持临时性定义,对于此例,会阻止后续的定义
c++中所有全局对象都被以初始化过的数据对待
对于 Point* heap = new Point;编译器并不会调用default constructor,只是 Point* heap = __new( sizeof(Point) )。delete亦是如此
对于*heap = local;编译器并不会调用copy assignment operator做拷贝,但只是像c那样做简单的bitwise
return操作也是,只是简单的bitwise,并没有调用copy constructor
现有如下片段:
class Point
{
public:
Point( float x = 0.0, float y = 0.0, float z = 0.0 ) : _x(x), _y(y), _z(z) { }
//没有copy constructor,copy operator,destructor
private:
float _x, _y, _z;
}
void do()
{
Point local1 = {1.0, 1.0, 1.0};
}
对于将class中成员设定常量值,使用explicit initialization list更有效率。因为当函数的活动记录(activation record)被放进堆栈,initialization list的常量即可放入local1内存中
活动记录过程的调用是过程的一次活动,当过程语句(及其调用)结束后,活动生命周期结束。变量的生命周期为其从被定义后有效存在的时间
但explicit initialization list也有不足:
若调用之前的例子,放在现在编译器也不会调用destructor,因为并没有显示地提供destructor
delete heap;
现有如下片段:
class Point
{
public:
Point( float x = 0.0, float y = 0.0, float z = 0.0 ) : _x(x), _y(y), _z(z) { }
virtual float z();
//没有copy constructor,copy operator,destructor
private:
float _x, _y;
}
导入了virtual functions会引发编译器对class Point的膨胀:
这种情况下,编译器在优化状态下可能会把object的连续内容拷贝到另一个object上,且不是memberwise。因此,编译器会尽量延迟nontrivial members的合成操作,直到遇到合适场合
例如之前的例子,此时就很有可能合成copy assignment operator,以及inline expansion。对于return,又因为合成copy constructor,函数内部又需改写;但若编译器支持NRV,内部会改写为constructor,此时将不用调用copy constructor
*heap = local;
return local;
T object;
对于以上定义,编译器会扩充每一个constructor。一般而言扩充如下:
实例:
class Point
{
public:
Point( float x = 0.0, float y = 0.0 );
Point( const Point& );
Point& operator=( const Point& );
virtual ~Point();
virtual float z() { return 0.0; }
protected:
float _x, _y;
};
class Line
{
Point _begin, _end;
public:
Line( float = 0.0, float = 0.0, float = 0.0, float = 0.0 );
Line( const Point&, const Point& ) : _end(end), _begin(begin);
draw();
...
};
//扩充
Line* Line::Line( Line* this, const Point&, const Point& )
{
this->begin.Point::Point( begin );
this->end.Point::Point( end );
return this;
}
//合成隐式的Line destructor。若Line派生自Point,合成的将会是virtual
Line a;
现有如下片段:
//假设每个class都定义了virtual function size(),传回class大小,每个constrcutor中调用size()
Point(x,y);
Point3d(x,y,z);
Vertex(x,y,z);
Vertex3d(x,y,z);
PVertex(x,y,z);
//当我们定义PVertex object,前五个constructor各自调用自己的size()
此时,constructor也需改变:
//改变后的constructor扩张
PVertex* PVertex::PVertex( PVertex* this, bool __most__derived, float x, float y, float z )
{
//调用virtual base constructor
if( __most_derived != false ) this->Point::Point(x,y);
//调用上层base class
this->Vertex3d::Vertex3d(x,y,z);
//初始化vptr
this->__vptr_PVertex = __vtbl_PVertex;
this->__vptr_Point__PVertex = __vtbl_Point__PVertex;
//size()
...
return this;
}
当然以上方案并不完美:
Point::Point( float x, float y ) : _x(x), _y(y) { }
Point3d::Point3d( float x, float y, float z ) : Point(x,y), _z(z) { }
此时,若声明PVertex,由于对其base class constructor的最新定义,其vptr将不再需要在每个base class constructor中被设定。因此,我们需要把constructor分裂为一个完整的object实例和sunobject实例
设计一个class,并以一个class object指定给另一个class object,我们有三种选择:
class对于default copy assignment operator,在以下情况,不会表现bitwise copy:
copy assignment operators并不表示bitwise copy是nontrivial。只有nontrivial instances才被合成
即使赋值由bitwise copy完成,并没有调用copy assignment operator,但还是需要提供一个copy constructor,以此打开NRV优化
尽可能不要允许一个virtual base class的拷贝操作。不要在任何virtual base class中声明数据
对于单一继承和多重继承,若class使用bitwise copy,一般不会合成copy constructor,就不会增加效率成本
对于虚拟继承,bitwise copy不再支持,而是合成copy assignment operator和inline copy constructor,导致成本大大增加。且继承体系复杂度增加,对象拷贝和构造的成本也会增加
destructor被扩展的方式。与constructor相似,但顺序相反:
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流