关于继承和动态内存分配

/*
总结:
当基类和派生类都采用动态内存分配时,派生类的析构函数、复制构造函数、赋值运算符都必须使用
相应的基类方法来处理基类元素。
1、对于析构函数,这是自动完成的。
2、对于复制构造函数,这是通过在初始化成员列表中调用基类的复制构造函数来完成的;
如果不这样做,将自动调用基类的默认构造函数
3、对于赋值运算符,这是通过使用作用域解析运算符显示地调用基类的赋值运算符来完成的。
*/

#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); //赋值构造函数
friend ostream & operator<<(ostream& os,const baseDMA& rs); //友元
};

//派生类 没有动态内存分配
class lackDMA : public baseDMA
{
private:
enum{COL_LEN=40};
char color[COL_LEN];
public:
lackDMA(const char* c=“blank”,const char* l=“null”,int r=0);
lackDMA(const char*c,const baseDMA& rs);
friend ostream & operator<<(ostream& os,const lackDMA& rs);
};

//派生类 有动态内存分配
class hasDMA : public baseDMA
{
private:
char style;
public:
hasDMA(const char
s=“none”,const char* l=“null”,int r=0);
hasDMA(const char* s,const baseDMA& rs);
hasDMA(const hasDMA& hs);
~hasDMA();
hasDMA & operator=(const hasDMA & rs);
friend ostream & operator<<(ostream& os,const hasDMA & rs);

};

#include “45.h”
#include

//类成员变量是动态内存分配 使用new动态分配
baseDMA::baseDMA(const char* l, int r)
{
label = new char[strlen(l)+1];
strcpy(label, l);
rating = r;
}

baseDMA::baseDMA(const baseDMA& rs)
{
label = new char[strlen(rs.label)+1];
strcpy(label, rs.label);
rating = rs.rating;
}
//析构函数 释放new出来的内存
baseDMA::~baseDMA()
{
delete[] label;
}
//赋值运算符
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;

}
//输出运算符 就是将内容存储到ostream的变量os中
ostream& operator<<(ostream& os, const baseDMA& rs)
{
os << “Label:” << rs.label << endl;
os << “Rating:” << rs.rating << endl;
return os;
}

//
//lackDMA派生类 疑问,这种情况下一定要初始化基类吗 如果是没有的参数的默认构造函数的情况呢
//回答:基类的构造函数是有参的,派生类的构造函数需要对基类进行初始化
//这里使用成员初始化列表
lackDMA::lackDMA(const char* c, const char* l, int r)
:baseDMA(l, r)
{
strncpy(color, c,COL_LEN-1);
color[COL_LEN-1] = ‘\0’; //字符串最后一个字符一定是结束符
}
lackDMA::lackDMA(const char*c, const baseDMA& rs) //参数里有拷贝构造函数
: baseDMA(rs)
{
strncpy(color, c, COL_LEN - 1);
color[COL_LEN-1] = ‘\0’;
}
ostream & operator<<(ostream& os, const lackDMA& rs)
{
os << (const baseDMA&)rs; //派生类调用基类友元 使用强转
os << “color:” << rs.color << endl;
return os;
}

//
hasDMA::hasDMA(const char* s, const char* l, int r)
:baseDMA(l,r)
{
style = new char[strlen(s)+1];
strcpy(style, s);
}
hasDMA::hasDMA(const char* s, const baseDMA& rs)
:baseDMA(rs)
{
style = new char[strlen(s)+1];
strcpy(style, s);
}
/*
hasDMA复制构造函数只能访问hasDMA的数据,因此它必须调用baseDMA复制构造函数来处理共享的baseDMA数据
注意:成员初始化列表将一个hasDMA引用传递给baseDMA构造函数
baseDMA复制构造函数将使用hasDMA参数的baseDMA部分来构造新对象的baseDMA部分
*/
hasDMA::hasDMA(const hasDMA& hs)
:baseDMA(hs) //注意一下这边 调用基类默认构造函数
{
style = new char[strlen(hs.style)+1];
strcpy(style, hs.style);
}

hasDMA::~hasDMA()
{
delete[] style;
}
/*
由于hasDMA也使用动态内存分配,所以它需要一个显示地赋值运算符。
作为hasDMA的方法,它只能直接访问hasDMA的数据。
然而,派生类的显示赋值运算符必须负责所有继承的baseDMA基类对象的赋值,
可以通过显示地调用基类赋值运算符来完成这项工作。
*/
hasDMA & hasDMA::operator=(const hasDMA & rs)
{
if (this == &rs)
{
return *this;
}
baseDMA::operator=(rs); //使用作用域解析符 调用基类赋值函数
delete[] style;

style = new char[strlen(rs.style)+1];
strcpy(style, rs.style);
return *this;

}
/*
因为友元不是成员函数,所以不能使用作用域解析运算符来指出要使用哪个函数。
解决方法:使用强制类型转换,以便匹配原型时能够选择正确的函数
*/
ostream & operator<<(ostream& os, const hasDMA & rs)
{
os << (const baseDMA&)rs; //强制类型转换(const baseDMA&)rs
os << “style” << rs.style << endl;
}

/*
类设计回顾:
1、默认构造函数
默认构造函数要么没有参数,要么所有的参数都有默认值

如果派生类构造函数的成员初始化列表中没有显示地调用基类构造函数,则编译器将使用基类的默认
构造函数来构造派生类对象的基类部分。在这种情况下,如果基类没有构造函数,将导致编译器阶段错误

2、返回对象和返回引用
直接返回对象与返回引用之间唯一的区别在于函数原型和函数头:
Star noval(const Star &);
Star& noval(const Star &);
返回对象涉及生成返回对象的临时副本
返回引用:调用和被调用的函数对同一个对象进行操作

然而,并不总是可以返回引用。函数不能返回在函数中创建的临时对象的引用,因为当函数结束时,临时对象就会消失。
在这种情况下,应返回对象,以生成一个调用程序可以使用的副本

3、使用const
Sta::Star(const char* s){…} //不能修改字符串s
void Star::show() const {…} //const来确保方法不修改调用它的对象

4、什么不能被继承
构造函数、析构函数、赋值运算符(赋值运算符的特征标随类而异,这是因为它包含一个类型为所属类的形参)
*/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值