C++基础(十三)
<第十三章—继承与动态内存分配>
问题:继承是怎样与动态内存分配进行互动的,如果基类使用动态内存分配,并重新定义赋值和复制构造函数,对派生类将产生什么影响?
1、创建一个基类:
头文件
#pragma once
#include"list.h" //一些基本的库
class BaseDma
{
private:
char* label;
int rating;
public:
BaseDma(const char* la = NULL, int ra = 0);
BaseDma(const BaseDma& b);
virtual ~BaseDma(){}
BaseDma& operator=(const BaseDma& b);
friend ostream& operator<<(ostream& os, BaseDma& b);
};
.cpp文件:
#include "Dma.h"
BaseDma::BaseDma(const char* la, int ra)
{
label = new char[strlen(la)+1];
strcpy(label, la);
rating = ra;
}
BaseDma::BaseDma(const BaseDma& b)
{
label = new char[strlen(b.label) + 1];
strcpy(label, b.label);
rating = b.rating;
}
BaseDma::~BaseDma()
{
delete[]label;
}
BaseDma& BaseDma::operator=(const BaseDma& b)
{
if (this == &b)
return *this;
else
{
delete[]label;
label = new char[strlen(b.label) + 1];
strcpy(label, b.label);
rating = b.rating;
return *this;
}
}
ostream& operator<<(ostream& os, BaseDma& b)
{
os << b.label << '\t' << b.rating << endl;
return os;
}
2、第一种情况:
派生类当中不使用new方法,那么派生类的析构函数可以省略,复制构造函数也可以省略,使用默认的复制构造函数
class NonewDma :public BaseDma
{
/*默认的复制构造函数执行成员复制,
这对于动态内存分配是不合适的,
但是对于没有使用new方法的成员来说是合适的*/
private:
enum{col_LEN=40};
char color[col_LEN];
public:
NonewDma(char*p=NULL,int ra=0,const char*pa="blank");
NonewDma(BaseDma&b, const char* pa = "blank");
~NonewDma(){} //可有可无
friend ostream& operator<<(ostream& os, NonewDma& b);
};
.cpp文件
ostream& operator<<(ostream& os,const BaseDma& b)
{
os << b.label << '\t' << b.rating << endl;
return os;
}
NonewDma::NonewDma(char* p, int ra, const char* pa) :BaseDma(p, ra)
{
strncpy(color, pa, col_LEN - 1);
color[col_LEN - 1] = '\0';
}
NonewDma::NonewDma(const BaseDma& b, const char* pa) :BaseDma(b)
{
strncpy(color, pa, col_LEN - 1);
color[col_LEN - 1] = '\0';
}
ostream& operator<<(ostream& os, const NonewDma& b)
{
os << (const BaseDma&)b << '\t';
os << b.color << endl;
return os;
}
3、第二种情况:派生类也是有new方法
还是上面的基类,再创建一个它的派生类:
头文件:
class HasnewDma :public BaseDma
{
/*
该派生类将会使用new方法开辟内存空间
*/
private:
char* style;
public:
HasnewDma(const BaseDma& b, const char* p = NULL);
HasnewDma(const char* la = NULL, int ra = 0, const char* p = NULL);
HasnewDma(const HasnewDma& b);
~HasnewDma();
HasnewDma& operator=(const HasnewDma& b);
friend ostream& operator<<(ostream& os, const HasnewDma& b);
};
.cpp文件:
//构造函数
HasnewDma::HasnewDma(const BaseDma& b, const char* p) :BaseDma(b)
{
style = new char[strlen(p) + 1];
strcpy(style, p);
}
//构造函数
HasnewDma::HasnewDma(const char* la , int ra, const char* p) : BaseDma(la, ra)
{
style = new char[strlen(p) + 1];
strcpy(style, p);
}
//复制构造函数
HasnewDma::HasnewDma(const HasnewDma& b)
{
style = new char[strlen(b.style) + 1];
strcpy(style, b.style);
}
//析构函数
HasnewDma::~HasnewDma()
{
delete[]style;
}
//重载运算符
HasnewDma& HasnewDma::operator=(const HasnewDma& b)
{
if (this == &b)
return *this;
else
{
BaseDma::operator=(b);
delete[]style;
style = new char[strlen(b.style) + 1];
strcpy(style, b.style);
return *this;
}
}
//友元函数定义
ostream& operator<<(ostream& os, const HasnewDma& b)
{
os << (BaseDma&)b << endl;
os << b.style << endl;
return os;
}
使用两种派生类:
int main()
{
BaseDma shirt("lp", 200);
NonewDma shirt2(shirt, "hello world!");
HasnewDma shirt1(shirt, "hello world!");
cout << shirt1 << endl;
cout << shirt2 << endl;
总结:如果派生类不使用new方法,那么就可以使用默认的复制构造函数和析构函数,如果使用了,就需要自定义复制构造函数和析构函数。当基类和派生类都使用动态内存分配时,派生类的析构函数、复制构造函数、赋值运算符都必须使用相应的基类方法处理基类元素。对于析构函数,这是自动完成的,对于构造函数,这是通过在初始化成员列表中调用基类的复制构造函数来完成的,如果不这样做,将自动调用基类的默认构造函数。对于赋值运算符,这是通过使用作用域解析运算符显式的调用基类的复制运算符来完成的。