对象复制语意(C++)
2016-05-24 22:16
246 查看
设计一个class,并以一个类对象指定给另一个类对象时,有三种选择
+ 1.什么都不做,实施默认行为
+ 2.提供一个explicit copy assignment operator
+ 3.显示拒绝把一个类对象指定给另一个
如果要实现第三点,不准将一个class object指定给另外一个类对象,那么只要将copy assignment operator声明为private,并且不提供定义即可。
如果默认的memberwise copy行为已经满足我们的需求,我们就不必去重写拷贝赋值操作符,反而这样,程序反倒执行得更慢
一个类对于默认的拷贝赋值符,下面这些情况是不会表现出bitwise copy语意
+ 1.当class 内含一个成员对象,而其类有一个拷贝赋值符
+ 2.一个类的基类有一个拷贝赋值操作符
+ 3.一个类声明任何的虚函数
+ 4.类继承自一个虚基类(不论这个基类有没有拷贝操作符)
说明:由于bitwise copy完成,把Point b拷贝到Point a,其间并没有拷贝赋值操作符被调用,从语意上或效率上考虑,这些都是我们所需要的。
假如现在要导入一个拷贝赋值操作符,说明该操作符在继承下的行为:
现在派生一个Point3d 类
如果没有Point3d定义一个拷贝赋值操作符,编译器就必须合成一个,合成得到的东西可能看起来是这样的:
拷贝赋值操作符有一个非正交性情况,它缺乏一个member assignment list(和成员初始化列表的东西),因此下列写法是错误的:
Line也不会拥有一个被合成出来的析构函数,因为Point并没有析构函数
2.如果class拥有成员类对象,而后者拥有析构函数,那么他们将会以声明顺序的相反顺序被调用
3.如果对象内含一个vptr,现在被重新设定,指向适当只base class的virtual table
4.如有任何直接的(上一层)nonvirtual 基类拥有析构函数,它会议其声明顺序的相反顺序被调用
5.如果有任何虚基类拥有的析构,那么他们会其原来的构造顺序的相反顺序被调用。
+ 1.什么都不做,实施默认行为
+ 2.提供一个explicit copy assignment operator
+ 3.显示拒绝把一个类对象指定给另一个
如果要实现第三点,不准将一个class object指定给另外一个类对象,那么只要将copy assignment operator声明为private,并且不提供定义即可。
class Pointy { public : Point(float x = 0.0,float y = 0.0); //... 没有virtual 函数 protected: float _x, _y; }
如果默认的memberwise copy行为已经满足我们的需求,我们就不必去重写拷贝赋值操作符,反而这样,程序反倒执行得更慢
一个类对于默认的拷贝赋值符,下面这些情况是不会表现出bitwise copy语意
+ 1.当class 内含一个成员对象,而其类有一个拷贝赋值符
+ 2.一个类的基类有一个拷贝赋值操作符
+ 3.一个类声明任何的虚函数
+ 4.类继承自一个虚基类(不论这个基类有没有拷贝操作符)
Point a,b; ... a = b;
说明:由于bitwise copy完成,把Point b拷贝到Point a,其间并没有拷贝赋值操作符被调用,从语意上或效率上考虑,这些都是我们所需要的。
假如现在要导入一个拷贝赋值操作符,说明该操作符在继承下的行为:
inline Point & Point::operator=( const Point &p) { _x = p._x; _y = p._y; return *this; }
现在派生一个Point3d 类
class Point3d : vitual public point { public : Point3d(float x = 0.0,float y = 0.0,float z = 0.0); // ... protected: float _z; }
如果没有Point3d定义一个拷贝赋值操作符,编译器就必须合成一个,合成得到的东西可能看起来是这样的:
// c++ 伪代码 inline Point3d & Point3d::operator = (Point3d * const this, const Point3d &p) { // 调用base class的函数实例 this->Point::operator=(p); //memberwise copy the derived class members _z = p.z; return *this; }
拷贝赋值操作符有一个非正交性情况,它缺乏一个member assignment list(和成员初始化列表的东西),因此下列写法是错误的:
//C++ 伪代码 inline Point3d & Point3d:: operator = (const Point3d &p3d):Point( p3d ),z(p3d._z) {}
析构语意学
如果类没有定义析构函数,那么只有在类内含的成员对象(或是类的基类)拥有析构函数的情况下,编译器才会自动合成一个,否则,析构被视为不需要,也不需要合成,例如下面的Point,默认情况下并没有被编译器合成出一个析构函数-甚至虽然它拥有一个虚函数class Point { public: Point(float x = 0.0,float y = 0.0); Point(const Point &); virtual float z(); private; float _x,_y; }; // 类似的道理如果把两个Point对象合成一个Line 类: class Line{ public: Line( const Point &, const Point &); // ... virtual draw(); //... protected: Point _begin,_end; };
Line也不会拥有一个被合成出来的析构函数,因为Point并没有析构函数
析构函数调用顺序
1.析构的函数本体首先被执行2.如果class拥有成员类对象,而后者拥有析构函数,那么他们将会以声明顺序的相反顺序被调用
3.如果对象内含一个vptr,现在被重新设定,指向适当只base class的virtual table
4.如有任何直接的(上一层)nonvirtual 基类拥有析构函数,它会议其声明顺序的相反顺序被调用
5.如果有任何虚基类拥有的析构,那么他们会其原来的构造顺序的相反顺序被调用。
相关文章推荐