当继承和动态内存分配的问题交织在一起的时候,我们考虑类实现的时候,就需要考虑更多的东西,先上代码:
1 #ifndef DMA_H 2 #define DMA_H 3 # include"iostream" 4 using namespace std; 5 class BaseDMA 6 { 7 //protected: //将父类私有成员变量private声明为protected,则继承类也可直接访问成员变量,private表明除了自己的类,其余的都不可直接访问(就算是继承子类也不可以) 8 //char* label; 9 //int rating; 10 private: 11 char* label; 12 int rating; 13 public: 14 BaseDMA(const char*l = "null", int r = 0);//构造函数 15 BaseDMA(const BaseDMA & rs);//拷贝函数 16 virtual ~BaseDMA();//虚析构函数,思考虚析构函数的意义,虚析构函数是为了避免多态时释放造成的内存泄露,因此,我们将基类的析构函数定义为虚函数是有好处的 17 BaseDMA & operator=(const BaseDMA & rs);//赋值运算符重载,返回 BaseDMA & 是为了连续赋值,那么这又是为什么呢??? 18 friend ostream& operator<<(ostream& os, const BaseDMA & rs);//实际上,这里表明了ostream是一个类,返回ostream&是为了连续显示,友元函数并不是类成员函数 19 }; 20 class LackDMA :public BaseDMA 21 { 22 23 private: 24 enum{COL_LEN=40};//采用这样的定义类型更便于程序的管理 25 char color[COL_LEN]; 26 public: //思考要不要重新设置构造函数,析构函数,以及赋值拷贝函数,以及为什么不需要修改 27 LackDMA(const char*c="black" , const char*l = "null", int r =0); 28 LackDMA(const char*c , const BaseDMA & rs); 29 LackDMA(const LackDMA & rs); 30 friend ostream& operator<<(ostream& os, const LackDMA & rs); 31 }; 32 33 class HasDMA :public BaseDMA 34 { 35 private: 36 char *style; 37 public: 38 HasDMA(const char*s = "none", const char*l = "null", int r = 0); 39 HasDMA(const char*s, const BaseDMA & rs); 40 HasDMA(const HasDMA & rs); 41 ~HasDMA();//为何上述lackdma代码段不需要重新定义析构函数,为何这里需要显示定义析构函数 42 HasDMA & operator=(const HasDMA & rs);//为何这里的赋值拷贝函数也需要重新定义 43 friend ostream& operator<<(ostream& os, const HasDMA & rs); 44 }; 45 #endif
上述类声明中,定义了一个基类BaseDMA,以及由该基类衍生的两个子类:LackDMA,HasDMA;其中,LackDMA类不涉及动态内存分配,HasDMA涉及动态内存分配。关于所涉及的其他知识细节,暂时不进行描述。下面给出类实现部分代码:
1 #include"dma.h" 2 # include "cstring" 3 using namespace std; 4 /////////BaseDMA类成员函数实现///////////////////////// 5 BaseDMA::BaseDMA(const char*l = "null", int r = 0) 6 { 7 label = new char[strlen(l) + 1]; 8 strcpy(label, l); 9 rating = r; 10 } 11 BaseDMA::BaseDMA(const BaseDMA & rs) 12 { 13 label = new char[strlen(rs.label) + 1]; 14 strcpy(label, rs.label); 15 rating = rs.rating; 16 } 17 18 BaseDMA::~BaseDMA()//在虚构函数实现的时候,并不需要virtual关键字 19 { 20 delete[] label; 21 } 22 //我们发现下面的赋值函数和采用类引用的拷贝函数基本功能一致,思考其内在联系 23 BaseDMA & BaseDMA:: operator=(const BaseDMA & rs)// 注意返回类型要放在作用域的前面 24 { 25 if (this == &rs)//思考在什么时候显示的使用this 指针 26 return *this; 27 delete[] label;//这里为何要使用delete[]删除原来 28 label = new char[strlen(rs.label) + 1]; 29 strcpy(label, rs.label); 30 rating = rs.rating; 31 return *this; 32 } //仔细思考这一段代码背后的机制 33 34 ostream& operator<<(ostream& os, const BaseDMA & rs)//需要注意的吧是。友元函数并不属于类的成员函数,因此这里并没有用BaseDMA::进行类作用域约束 35 { 36 os << "Label: " << rs.label << endl; 37 os << "rating: " << rs.rating << endl; 38 return os;//返回os是为了形成对<<a<<b的连续显示效果 39 } 40 ///////////////////////LackDMA类成员函数实现/////////////////////////// 41 LackDMA::LackDMA(const char*c = "black", const char*l = "null", int r = 0) :BaseDMA(l, r) 42 { 43 strncpy(color, c, 39);//注意这里的拷贝函数不再是strcpy而是strncpy; 44 color[39] = '