派生类的复制构造函数与赋值运算符

先来看下面这个例子:

//class.h#ifndef CLASS_HEAD_FILE#define CLASS_HEAD_FILEclass base {public:base();base(const base&);base& operator=(base& bObj);int getBaseNum(void) { return b_iNum; }void setBaseNum(int Num) { b_iNum = Num; }virtual ~base();private:int b_iNum;};class derived : public base {public:derived();derived(const derived&);derived& operator=(derived&);int getDerivedNum(void) { return d_iNum; }~derived();private:int d_iNum;};#endif // CLASS_HEAD_FILE//class.cpp#include "class.h"#include <iostream>base::base() : b_iNum(10){std::cout << "base() is called! " << std::endl;}base::~base() {std::cout << "~base() is called! " << std::endl;}base::base(const base& bObj) {std::cout << "base CopyFunction is called! " << std::endl;b_iNum = bObj.b_iNum;}base& base::operator=(base& bObj) {std::cout << "base::operator=(base& bObj) is called! " << std::endl;b_iNum = bObj.b_iNum;return *this;}derived::derived() : d_iNum(20){std::cout << "derived() is called! " << std::endl;}derived::~derived() {std::cout << "~derived() is called! " << std::endl;}derived::derived(const derived& dObj){std::cout << "derived CopyFunction is called! " << std::endl;d_iNum = dObj.d_iNum;}derived& derived::operator=(derived& dObj) {if(this == &dObj)return *this;std::cout << "derived::operator=(derived& bObj) is called! " << std::endl;d_iNum = dObj.d_iNum;return *this;}//testMain.cpp#include "class.h"#include <iostream>int main() {derived d1;d1.setBaseNum(100);std::cout << "now execute the copy procedure…\n\n";derived d2(d1);std::cout << "now execute the assignment procedure…\n\n";derived d3;d3 = d1;std::cout << "\nThe results are as follows:\n" << std::endl;std::cout << "d1.getBaseNum() = " << d1.getBaseNum() << std::endl;std::cout << "d1.getDerivedNum() = " << d1.getDerivedNum() << std::endl;std::cout << "d2.getBaseNum() = " << d2.getBaseNum() << std::endl;std::cout << "d2.getDerivedNum() = " << d2.getDerivedNum() << std::endl;std::cout << "d3.getBaseNum() = " << d3.getBaseNum() << std::endl;std::cout << "d3.getDerivedNum() = " << d3.getDerivedNum() << std::endl;}

对于上面这个程序,输出结果为:

base() is called!derived() is called!now execute the copy procedure…base() is called!derived CopyFunction is called!now execute the assignment procedure…base() is called!derived() is called!derived::operator=(derived& bObj) is called!The results are as follows:d1.getBaseNum() = 100d1.getDerivedNum() = 20d2.getBaseNum() = 10d2.getDerivedNum() = 20d3.getBaseNum() = 10d3.getDerivedNum() = 20~derived() is called!~base() is called!~derived() is called!~base() is called!~derived() is called!~base() is called!

下面我们分四个部分来分析上面的程序的输出结果。

对于默认构造函数:

我们看到,在派生类的默认构造函数中,并不直接初始化派生类的基类部分的成员,而是调用基类的默认构造函数初始化基类的部分。这里,如果派生类的默认构造函数没有指明调用哪个基类构造函数对派生类的基类部分进行初始化,则编译器会默认调用基类的默认构造函数。当然,你也可以手动指明调用基类的特定的构造函数。每次都是先初始化派生类的基类部分成员,再初始化派生类的新的自有成员。还有一点也很重要,就是派生类只对其直接基类负责,并不需要考虑基类的基类怎么初始化,因为那是基类的事情了。

对于复制构造函数:

它需要完成的工作也是两部分:调用基类的复制构造函数完成派生类的基类部分的复制,然后再复制派生类自有的部分。但正如上例中我们看到的,,这时,如果不手动指明调用基类的哪个复制构造函数,则编译器是不会默认指派的。所以我们才会惊奇地看到,由d1复制而来的d2对象中的基类部分的数据,和d1不一样。

对于赋值操作符:

如果不手动指明调用基类的哪个赋值操作符,编译器也是不会默认指派的。所以我们才会又一次惊奇地看到,d3 = d1; 但是d3对象中的基类部分的数据,和d1不一样。

对于析构函数:

我们看到,析构函数的顺序为先析构派生类对象的自有部分,再析构本派生类对象的基类部分。而且不用手动指明,编译器会自动调用基类的析构函数,因为基类的析构函数只有一个嘛!对于本例,不把基类的析构函数声明为virtual,也会正常执行。但是强烈建议把基类的析构函数声明为virtual,因为这样,就可以使用基类引用或指针 正常释放派生类的对象了。所以说,一定要把基类中的析构函数定义为虚函数。

综上所述,想要解决这类问题很简单,对于后两者,只要手动指明需要调用的基类函数即可。修改后class.cpp 的程序如下:

derived::derived(const derived& dObj) :base(dObj) {std::cout << "derived CopyFunction is called! " << std::endl;d_iNum = dObj.d_iNum;}derived& derived::operator=(derived& dObj) {if(this == &dObj)return *this;base::operator=(dObj);std::cout << "derived::operator=(derived& bObj) is called! " << std::endl;d_iNum = dObj.d_iNum;return *this;}修改之后的输出结果是:base() is called!derived() is called!now execute the copy procedure…base CopyFunction is called!derived CopyFunction is called!now execute the assignment procedure…base() is called!derived() is called!base::operator=(base& bObj) is called!derived::operator=(derived& bObj) is called!The results are as follows:d1.getBaseNum() = 100d1.getDerivedNum() = 20d2.getBaseNum() = 100d2.getDerivedNum() = 20d3.getBaseNum() = 100d3.getDerivedNum() = 20~derived() is called!~base() is called!~derived() is called!~base() is called!~derived() is called!~base() is called!

我们可以看到,此时输出结果正常了!!!

只要你扬帆,便会有八面来风。启程了,人的生命才真正开始。

派生类的复制构造函数与赋值运算符

相关文章:

你感兴趣的文章:

标签云: