这一节主要想讲一下在你实现了一个子类继承了一个基类的情况下,你的构造、析构、拷贝构造、重载赋值运算符应该怎么改变。
第一种情况:基类使用new开辟动态内存,子类不使用new
- #include
- #include
- using namespace std;
-
- class baseDMA
- {
- private:
- char *label;
- int rating;
- public:
- baseDMA(const char *l = "null", int r=0);
- baseDMA(const baseDMA &rs);
- virtual ~baseDMA();
- baseDMA &operator=(const baseDMA &rs);
- };
-
- class lacksDMA:public baseDMA
- {
- private:
- char color[40];
- public:
-
- };
上面代码只给出声明不给出实现,只要懂得意思即可。
对于我们的子类lacksDMA,因为其并没有开辟动态内存空间,因此其不需要析构函数(使用默认析构函数即可) 。
对于拷贝构造函数,因为lacksDMA继承了baseDMA,因此其默认拷贝构造函数即为baseDMA的拷贝构造函数,并且由于之前说的父类引用可以指向子类,因此将子类传给父类的拷贝构造函数完全可以,因此lacksDMA的拷贝构造的结果是拷贝了与baseDMA共有的部分。
对于赋值来说也是一样,类的默认赋值运算符将自动使用基类的赋值运算符来对基类组件进行赋值!
第二种情况:派生类也使用new
接下来我们新定义一个子类hasDMA继承baseDMA,并在子类中使用new开辟动态内存。
- class hasDMA:public baseDMA
- {
- private:
- char *style;
- public:
- hasDMA(const hasDMA &hs);
- ~hasDMA();
- hasDMA &operator=(const hasDMA &hs);
- };
-
- baseDMA::~baseDMA()
- {
- delete [] label;
- }
-
- hasDMA::~hasDMA()
- {
- delete [] style;
- }
-
- baseDMA::baseDMA(const baseDMA &rs)
- {
- label = new char[strlen(rs.label) + 1];
- strcpy(label, rs.label);
- rating = rs.rating;
- }
-
- hasDMA::hasDMA(const hasDMA &hs):baseDMA(hs)
- {
- style = new char[strlen(hs.style) + 1];
- strcpy(style, hs.style);
- }
-
- baseDMA &baseDMA::operator=(const baseDMA &rs)
- {
- if(this == &rs)
- return *this;
- delete [] label;
- label = new char[strlen(rs.label) + 1];
- strcpy(label, rs.label);
- rating = rs.rating;
- return *this;
- }
-
- hasDMA &hasDMA::operator=(const hasDMA &hs)
- {
- if (this == &hs)
- return *this;
- baseDMA::operator=(hs);
- delete [] style;
- style = new char[strlen(hs.style) + 1];
- strcpy(style,hs.style);
- return *this;
- }
因为我们在hasDMA类中开辟类动态内存空间,因此hasDMA析构函数得进行释放,并补上开始的baseDMA析构函数的实现。
我们来看看拷贝构造函数,父类的拷贝构造函数没什么好说的,主要是子类,子类先用初始化列表将要传进来进行拷贝的子类对象传给父类,这是因为首先父类引用可以指向子类所以可以传,又因为我们对子类进行拷贝,子类中还有一些继承父类的组件得传给父类才能使得全部拷贝进去吧,否则只拷贝了子类自己特有的部分,因为我们必须传!
最后我们看看重载赋值运算符,其实很容易想到重载赋值运算符其实和拷贝构造函数的功能是差不多的,因此基类的重载赋值运算符和拷贝构造函数的实现差不多。主要看看子类的重载赋值运算符中的baseDMA::operator=(hs)这句,通过使用函数表示法,而不是运算符表示法,可以使作用域解析运算符,实际上这一句的含义等同于 *this=hs;这里和上面子类的拷贝构造函数一样,也要先将父类拷贝了。
小tips:
为什么拷贝构造函数都要用引用传递,因为之前说过拷贝构造函数实际上是变量的赋值,因此使用引用会比较快而且使用引用也比较方便。
参考资料:
C++ Prime Plus第六版