标签:
T object;时,实际上会发生什么事情呢?如果T有一个constructor(不论是由user提供或是由编译器合成),它会被调用.这很明显,比较不明显的是,constructor的调用真正伴随了什么?
virtual destructor如下: class Point { public: Point(float x = 0.0, float y = 0.0); Point(const Point &); // copy constructor Point &operator=(const Point &); // copy assignment operator virtual ~Point(); // virtual destructor virtual float z() { return 0.0; } protected: float _x, _y; };在开始介绍Point的继承体系之前,先看看Line class 的声明和扩充结果,它由_begin和_end两个点构成:
class Line { Point _begin, _end; public: Line(float = 0.0, float = 0.0, float = 0.0, float = 0.0); Line(const Point &, const Point &); draw(); };每一个 explicit constructor都会被扩充以调用其两个member class objects的constructors.如果定义constructor如下:
Line::Line(const Point &begin, const Point &end) : _end(end), _begin(begin) {}它会被编译器扩充并转换为:
// C++伪代码:Line constructor的扩充 Line *Line::Line(Line *this, const Point &begin, const Point &end) { this->_begin.Point::Point(begin); this->_end.Point::Point(end); return this; }由于Point声明了copy constructor,一个copy operator,以及一个destructor(本例为 virtual),所以Line class 的implicit copy constructor,copy operator和destructor都将有实际功能(nontrivial).
Line a;时,implicit Line destructor会被合成出来(如果Line派生自Point,那么合成出来的destructor将会是 virtual.然而由于Line只是内带Point objects而非继承自Point,所以被合成出来的destructor只是nontrivial而已).在其中,它的member class objects的destructor会被调用(以其构造的相反顺序):
// C++伪代码:合成出来的Line destructor inline void Line::~Line(Line *this) { this->_end.Point::~Point(); this->_begin.Point::~Point(); }当然,如果Point destructor是 inline 函数,那么每一个调用操作会在调用地点被扩展开来.请注意,虽然Point destructor是 virtual,但其调用操作(在containing class destructor中)会被静态地决议出来(resolved statically).
Line b = a;时,implicit Line copy constructor会被合成出来,成为一个 inline public member.
a = b;时,implicit copy assignment operator会被合成出来,成为一个 inline public member.
if (this == &rhs) return *this;在一个由程序员供应的copy operator中忘记检查自我指派(赋值)操作是否失败,是新手极易陷入的一项错误,例如:
// 使用者供应的copy assignment operator // 忘记提供一个自我拷贝时的筛选 String &String::operator=(const String &rhs) { // 这里需要筛选(在释放资源之前) delete []str; str = new char[strlen(rhs.str) + 1]; }这样一个警告信息是有帮助,"在一个copy operator中,面对自我拷贝缺乏一个筛选操作;但却有一个delete operator对应某个member操作".
class Point3d : public virtual Point { public: Point3d(float x = 0.0, float y = 0.0, float z = 0.0) : Point(x, y), _z(z) {} Point3d(const Point3d &rhs) : Point(rhs), _z(rhs._z) {} ~Point3d(); Point3d &operator=(const Point3d &); virtual float z() { return _z; } protected: float _z; };传统的"constructor扩充现象"并没有用,这是因为 virtual base class 的"共享性"的缘故:
// C++伪代码:不合法的constructor扩充内容 Point3d *Point3d::Point3d(Point3d *this, float x, float y, float z) { this->Point::Point(x, y); this->__vptr_Point3d = __vtbl_Point3d; this->__vptr_Point3d__Point = __vtbl_Point3d_Point; this->_z = rhs._z; return this; }上面的Point3d constructor扩充内容有什么错误?
class Vertex : virtual public Point { ... }; class Vertex3d : public Point3d, public Vertex { ... }; class PVertex : public Vertex3d { ... };Vertex的constructor必须也调用Point的constructor.然而,当Point3d和Vertex同为Vertex3d的subobjects时,它们对Point constructor的调用操作一定不可以发生,取而代之的是,作为一个最底层的 class,Vertex3d有责任将Point初始化,而更往下的继承,则由PVertex(不再是Vertex3d)来负责完成"被共享的Point subobject"的构造.
// C++伪代码:在virtual base class情况下的constructor扩充内容 Point3d *Point3d::Point3d(Point3d *this, bool __most_derived, float x, float y, float z) { if (__most_derived != false) this->Point::Point(x, y); this->__vptr_Point3d = __vtbl_Point3d; this->__vptr_Point3d_Point = __vtbl_Point3d__Point; this->_z = rhs._z; return this; }在更深层的继承情况下,例如Vertex3d,当调用Point3d和Vertex的constructor时,总是会把__most_derived参数设为 false,于是就压制了两个constructors中对Point constructor的调用操作.
// C++伪代码:在virtual base class情况下的constructor扩充内容 Vertex3d *Vertex3d::Vertex3d(Vertex3d *this, bool __most_derived, float x, float y, float z) { if (__most_derived != false) this->Point::Point(x, y); // 调用上一层base classes // 设定__most_derived为false this->Point3d:::Point3d(false, x, y, z); this->Vertex::Vertex(false, x, y); // 设定vptrs // 插入user mode return this; }这样的策略得以保持语意的正确无误.例如,当定义:
Point3d origin;时,Point3d constructor可以正确地调用其Point virtual base class subobject.而当定义:
Vertex3d cv;时,Vertex3d constructor正确地调用Point constructor.Point3d和Vertex的constructor会做每一件该做的事情——对Point的调用操作除外.
Point(x, y); Point3d(x, y, z); Vertex(x, y, z); Vertex3d(x, y, z); PVertex(x, y, z);假设这个继承系统中的每一个 class 都定义了一个 virtual function size().该函数负责返回 class 的大小,如果写:
PVertex pv; Point3d p3d; Point *pt = &pv;那么这个调用操作:
pt->size();将传回PVertex的大小,而:
pt = &p3d; pt->size();将传回Point3d的大小.
Point3d::Point3d(float x, float y, float z) : _x(x), _y(y), _z(z) { if (spyOn) cerr < "Within Point3d::Point3d()" << " size: " << size() << endl; }当定义PVertex object时,前述的五个constructors会如何?每一次size()调用会被决议为PVertex::size()吗?或者每次调用会被决议为"当前正在执行的constructor所对应的class"的size()函数实体?
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 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 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; }这就完美地解决了所说的有关限制虚拟机制的问题,但是,这真是一个完美的解答?假设Point Constructor定义为:
Point::Point(flaot x, float y) : _x(x), _y(y) {}Point3d constructor定义为:
Point3d::Point3d(float x, float y, float z) : Point(x, y), _z(z) {}更进一步,假设Vertex和Vertex3d constructor有类似的定义.是否能够看出解决办法并不完美?
版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:
原文地址:http://blog.csdn.net/yiranant/article/details/47617795