继承类使用动态内存分配,派生类如何使用基类的友元函数,参数为基类对象引用和按值传递基类对象时传递继承类参数的区别
//class.h
#ifndef _CLASS_H_
#define _CLASS_H_
#include<iostream>
// Base class
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 std::ostream& operator<<(std::ostream& os, const baseDMA& rs);
};
// Derived class
class lacksDMA :public baseDMA
{
private:
enum{COL_LEN=40}; //相当于 static const int COL_LEN = 40;
//--- 若为static int COL_LEN则要么在定义时就初始化,要不就只能在实现文件中通过 int lacksDMA::COL_LEN = 40来进行初始化
char color[COL_LEN];
public:
lacksDMA(const char* c = "blank", const char* l = "null", int r = 0); //第一个参数是派生类新加的数据,后两个数据是基类的数据
lacksDMA(const char* c, const baseDMA& ls);
friend std::ostream&operator<<(std::ostream& os, const lacksDMA& ls); //iostream流作为返回类型和参数时必须为引用,因为没有公共的复制构造函数
};
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& hs); //默认参数只用从右往左开始设置
hasDMA(const hasDMA& hs);
~hasDMA();
hasDMA& operator=(const hasDMA& hs);
friend std::ostream& operator<<(std::ostream& os, const hasDMA& hs);
};
#endif
// fuc.cpp
#include"class.h"
#include<cstring> //strlen() strcpy()
#pragma warning(disable:4996)
using namespace std;
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;
}
baseDMA::~baseDMA()
{
delete[] label;
}
baseDMA& baseDMA::operator=(const baseDMA& rs)
{
if (this == &rs)
{
return *this;
}
else
{
delete[] label; //重载赋值运算符,在其深度复制之前,应当先进行delete防止浪费内存
label = new char[strlen(rs.label) + 1];
strcpy(label, rs.label);
rating = rs.rating;
return *this;
}
}
//友元函数(无需声明其位于哪个类中,因为友元函数不是成员函数)
std::ostream& operator<<(std::ostream& os, const baseDMA& rs)
{
os << "Label: " << rs.label << std::endl;
os << "Rating: " << rs.rating << std::endl;
return os;
}
lacksDMA::lacksDMA(const char* c, const char* l, int r) :baseDMA(l, r) //通过成员初始化来先创建基类成员
{
strncpy(color, c, 39);
color[30] = '\0';
}
lacksDMA::lacksDMA(const char* c, const baseDMA& ls) :baseDMA(ls)
{
strncpy(color, c, 39);
color[30] = '\0';
}
std::ostream& operator<<(std::ostream& os, const lacksDMA& ls)
{
os << (const baseDMA&)ls; //通过强制类型转换,将lacksDMA&参数转换为baseDMA&参数,以匹配基类的友元函数并使用
os << "Color: " << ls.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& hs):baseDMA(hs)
{
style = new char[strlen(s) + 1];
strcpy(style, s);
}
hasDMA::~hasDMA()
{
delete[] style;
}
//派生类的复制构造函数:通过成员初始化调用基类的复制构造函数复制基类的部分,同时要进行成员初始化
hasDMA::hasDMA(const hasDMA& hs) :baseDMA(hs)
{
style = new char[strlen(hs.style) + 1];
strcpy(style, hs.style);
}
//派生类的重载赋值运算符:通过basename::operator=(paremeter)访问基类的重载赋值运算符,来实现基类部分的赋值
hasDMA& hasDMA::operator=(const hasDMA& hs)
{
if (this == &hs)
{
return *this;
}
else
{
baseDMA::operator=(hs); //实现基类数据的赋值
delete[] style;
style = new char[strlen(hs.style) + 1];
strcpy(style, hs.style);
return *this;
}
}
std::ostream& operator<<(std::ostream& os, const hasDMA& hs)
{
os << (baseDMA&)hs; //强制类型转换以访问基类的友元函数
os << "Style: " << hs.style << endl;
return os;
}
//main.cpp
#include"class.h"
using namespace std;
int main()
{
baseDMA shirt("Portabelly", 8);
lacksDMA ballon("red", "Blimpo", 4);
hasDMA map("Mercator", "Buffalo Keys", 5);
cout << "Displaying baseDMA object: " << endl;
cout << shirt << endl;
cout << "Displaying lacksDMA object:" << endl;
cout << ballon << endl;
cout << "Displaying hasDMA object: " << endl;
cout << map << endl;
lacksDMA ballon2(ballon); //复制构造函数
cout << "Result of lacksDMA copy: " << endl;
cout << ballon2 << endl;
hasDMA map2;
map2 = map;
cout << "Result of hasDMA assignment: " << endl;
cout << map2 << endl;
system("pause");
return 0;
}
知识点:
1.继承类使用动态分配:
1):自定义析构函数:要配套的使用delete释放new开辟的内存空间
2):自定义复制构造函数:派生类的复制构造函数会同时调用基类的复制构造函数来对基类部分的数据进行复制(通过成员初始化来完成).
eg:
//派生类的复制构造函数:通过成员初始化调用基类的复制构造函数复制基类的部分,同时要进行成员初始化
hasDMA::hasDMA(const hasDMA& hs) :baseDMA(hs)
{
style = new char[strlen(hs.style) + 1];
strcpy(style, hs.style);
}
3):重载赋值运算符:调用重载赋值运算符时也将调用基类的重载赋值运算符来对基类部分的数据进行赋值(通过Classname::operator=(parameter)来完成,相当于调用基类的重载赋值运算符,并传递一个参数)
eg:
//派生类的重载赋值运算符:通过basename::operator=(paremeter)访问基类的重载赋值运算符,来实现基类部分的赋值
hasDMA& hasDMA::operator=(const hasDMA& hs)
{
if (this == &hs)
{
return *this;
}
else
{
baseDMA::operator=(hs); //实现基类数据的赋值
delete[] style;
style = new char[strlen(hs.style) + 1];
strcpy(style, hs.style);
return *this;
}
}
2.派生类如何使用基类的友元函数 -- 通过强制类型转换(将派生类参数强制转换为基类参数)
(因为友元函数不是成员函数,无法使用范围解析运算符' :: '来访问其中的函数,所以只能通过强制类型转换来转换参数类型,以匹配相应的函数)
eg:
std::ostream& operator<<(std::ostream& os, const lacksDMA& ls)
{
os << (const baseDMA&)ls; //通过强制类型转换,将lacksDMA&参数转换为baseDMA&参数,以匹配基类的友元函数并使用
os << "Color: " << ls.color << endl;
return os;
}
std::ostream& operator<<(std::ostream& os, const hasDMA& hs)
{
os << (baseDMA&)hs; //强制类型转换以访问基类的友元函数
os << "Style: " << hs.style << endl;
return os;
}
3.参数为基类对象引用和按值传递基类对象时传递继承类参数的区别:
eg:
void show(const Brass& rba)
{
rba.viewAcct(); //按引用传递,若传递的是一个派生类,rba便是派生类对象,可以访问派生类的函数
cout << endl;
}
void inadequate(Brass ba)
{
ba.viewAcct(); //按值传递,则ba是Brass的构造函数创建的一个Brass对象,只能访问基类的函数
cout << endl;
}
//因此,传递类对象参数时应尽量使用引用或者指针。