C++ Primer Plus 第十三章答案 类继承

复习题

//13.10
//1
基类的公有成员成为派生类的公有成员。基类的保护成员成为派生类的保护成员。
基类的私有成员被继承,但不能直接访问。

//2
不能继承构造函数,析构函数,赋值运算符和友元。

//3
返回类型为void则可以使用单个赋值而不能使用连锁赋值。
如果返回对象而不是引用,则该方法的执行速度变慢,因为返回语句需要复制对象。

//4
按派生的顺序调用构造函数,最早的构造函数最先调用,调用析构函数的顺序正好相反。

//5
需要,每个类都需要自己的构造函数,如果派生类没有添加新成员,构造函数可以为空但必须存在。

//6
只调用派生类方法,它取代基类定义,只有当派生类没有重新定义方法或使用作用域解析运算符时
才会调用基类方法,然而,应该把所有要重新定义的函数声明为虚函数。

//7
派生类构造函数使用new或new[]来初始化类的指针成员,则应该定义一个赋值运算符
更普遍地说,如果对于派生类成员默认赋值不正确,则应该定义赋值运算符。

//8
派生类对象的地址可以赋给基类指针,但只有通过显式类型转换才可以把基类的地址赋给派生类
指针,而使用这样的指针不一定安全。

//9
可以把派生类对象赋给基类对象,派生类中新增的数据成员都不会传递给基类对象,使用基类的
赋值运算符。但是仅当派生类定义了转换运算符(即包含将基类引用作为唯一参数的构造函数)
或使用基类为参数的赋值运算符时,相反方向的赋值才有可能。

//10
C++允许基类引用指向该基类派生来的任何类型。

//11
按值传递对象将调用复制构造函数。由于形参是基类对象,因此调用基类的复制构造函数。复制
构造函数以基类引用为参数,可以接受作为参数传递的派生类对象。最终结果是生成一个新的
基类对象,其成员对应于派生对象的基类部分。

//12
按引用传递可以确保函数从虚函数受益,另外,按引用传递可以节省内存和时间,尤其对于大型对象
按值传递的主要优点在于可以保护原始数据,但可以通过将引用作为const类型传递达到同样的目的。

//13
a,调用基类方法
b,调用派生类方法

//14
首先,这种类型不符合is-a模型,因此公有继承不适用。
其次House的area()定义隐藏了area()的Kitchen版本,不管这两个方法的特征标是否相同。
ps:只要基类定义了virtual,继承类的该函数也具有virtual属性。

practice 1

//classic.h
#pragma once
#include<string>
class Cd {
	char performers[50];
	char label[20];
	int selections;
	double playtime;
public:
	Cd(const char* s1, const char* s2, int n, double x);
	Cd();
	virtual ~Cd();
	virtual void Report()const;
};
class Classic :public Cd {
	std::string works;
public:
	Classic(const std::string& s, const char* s1, const char* s2, int n, double x);
	Classic();
	virtual ~Classic();
	virtual void Report()const;
	Classic& operator=(const Classic& cl);
};



//classic.cpp
#include<iostream>
#include"classic.h"
using std::cout;
using std::endl;
Cd::Cd(const char* s1, const char* s2, int n, double x) : selections(n), playtime(x) {
	strcpy_s(performers, s1);
	strcpy_s(label, s2);
}
Cd::Cd() :performers("null"), label("null"), selections(0), playtime(0) {}
Cd::~Cd() {}
void Cd::Report()const {
	cout << "performers: " << performers << endl;
	cout << "label: " << label << endl;
	cout << "selections: " << selections << endl;
	cout << "playtime: " << playtime << endl;
}
Classic::Classic(const std::string& s, const char* s1, const char* s2, int n, double x) :
	works(s), Cd(s1, s2, n, x) {}
Classic::Classic() : works("null"), Cd() {}
Classic::~Classic() {}
void Classic::Report()const {
	cout << "works: " << works << endl;
	Cd::Report();
}
Classic& Classic::operator=(const Classic& cl) {
	if (this == &cl)
		return *this;
	Cd::operator=(cl);
	works = cl.works;
	return *this;
}


//main.cpp
#include<iostream>
#include"classic.h"
using namespace std;
void Bravo(const Cd& disk) {
	disk.Report();
}
int main() {
	Cd c1("Beatles", "Capitol", 14, 35.5);
	Classic c2 = Classic("pianosonata in B flat, Fantasia in C",
		"Alfred Brendel", "Philips", 2, 57.17);
	Cd* pcd = &c1;

	cout << "Using object directly:\n";
	c1.Report();
	cout << endl;
	c2.Report();
	cout << endl << endl;

	cout << "Using type cd* pointer to objects:\n";
	pcd->Report();
	pcd = &c2;
	cout << endl;
	pcd->Report();
	cout << endl << endl;

	cout << "Calling a function with a Cd reference argument:\n";
	Bravo(c1);
	cout << endl;
	Bravo(c2);
	cout << endl << endl;

	cout << "Testing assignment:\n";
	Classic copy;
	copy = c2;
	copy.Report();
	return 0;
}

practcie 2

只改变实现不改变接口,因此main.cpp文件不用更改

//classic.h
#pragma once
class Cd {
	char* performers;
	char* label;
	int selections;
	double playtime;
public:
	Cd(const char* s1, const char* s2, int n, double x);
	Cd(const Cd& c);
	Cd();
	virtual ~Cd();
	virtual void Report()const;
	Cd& operator=(const Cd& c);
};
class Classic :public Cd {
	char* works;
public:
	Classic(const char* s, const char* s1, const char* s2, int n, double x);
	Classic(const Classic& cl);
	Classic();
	virtual ~Classic();
	virtual void Report()const;
	Classic& operator=(const Classic& cl);
};



//classic.cpp
#include<iostream>
#include"classic.h"
#include<string>
#pragma warning(disable :4996)
using std::cout;
using std::endl;
using std::strcpy;
using std::strlen;
Cd::Cd(const char* s1, const char* s2, int n, double x) : selections(n), playtime(x) {
	performers = new char[strlen(s1) + 1];
	strcpy(performers, s1);
	label = new char[strlen(s2) + 1];
	strcpy(label, s2);
}
Cd::Cd(const Cd& c) {
	performers = new char[strlen(c.performers) + 1];
	strcpy(performers, c.performers);
	label = new char[strlen(c.label) + 1];
	strcpy(label, c.label);
	selections = c.selections;
	playtime = c.playtime;
}
Cd::Cd() :selections(0), playtime(0) {
	performers = nullptr;
	label = nullptr;
}
Cd::~Cd() {
	delete[]performers;
	delete[]label;
}
void Cd::Report()const {
	cout << "performers: " << performers << endl;
	cout << "label: " << label << endl;
	cout << "selections: " << selections << endl;
	cout << "playtime: " << playtime << endl;
}
Cd& Cd::operator=(const Cd& c) {
	delete[]performers;
	delete[]label;
	performers = new char[strlen(c.performers) + 1];
	label = new char[strlen(c.label) + 1];
	strcpy(performers, c.performers);
	strcpy(label, c.label);
	selections = c.selections;
	playtime = c.playtime;
	return *this;
}
Classic::Classic(const char* s, const char* s1, const char* s2, int n, double x) :
	Cd(s1, s2, n, x) {
	works = new char[strlen(s) + 1];
	strcpy(works, s);
}
Classic::Classic(const Classic& cl) : Cd(cl) {
	works = new char[strlen(cl.works) + 1];
	strcpy(works,cl.works);
}
Classic::Classic() : works(nullptr), Cd() {}
Classic::~Classic() {
	delete[]works;
}
void Classic::Report()const {
	cout << "works: " << works << endl;
	Cd::Report();
}
Classic& Classic::operator=(const Classic& cl) {
	if (this == &cl)
		return *this;
	Cd::operator=(cl);
	delete[]works;
	works = new char[strlen(cl.works) + 1];
	strcpy(works, cl.works);
	return *this;
}

practice 3

这题有一个巨坑,书上的13.10有一个continue用来清除输入,但是书上的程序是读取的数字,用的cin,而练习题要用cin.getline(),而且由于前面用的cin读取1,2,3判断创建哪一种类,需要一个cin.get()读取换行符。这时候巨坑出现了,如果按书上的程序抄的同时发现没有用cin.get()导致color和style读不进去然后加上cin.get(),我换了七八个位置加cin.get(),能解决问题,但是会要多读一个换行符才能进去下一个循环,我这个憨批花了两个小时一直没发现问题,以为是cin.get()的问题,现在想想就是因为有个while——continue那个循环,必须读一个字符,所以要多输入一个换行符,现在人已经被自己气死了。。

//dma.h
#pragma once
#include<iostream>
class base {
	char* label;
	int rating;
public:
	base(const char* l = "null", int r = 0);
	base(const base& b);
	virtual ~base() = 0;
	base& operator=(const base& b);
	virtual void View() = 0;
};
/
class baseDMA :public base {
public:
	baseDMA(const char* l = "null", int r = 0);
	virtual ~baseDMA();
	virtual void View();
};
//
class lacksDMA :public base {
	enum { 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 base& b);
	virtual ~lacksDMA();
	virtual void View();
};
//
class hasDMA :public base {
	char* style;
public:
	hasDMA(const char* s = "none", const char* l = "null", int r = 0);
	hasDMA(const char* s, const base& b);
	hasDMA(const hasDMA& hd);
	virtual ~hasDMA();
	hasDMA& operator=(hasDMA& hd);
	virtual void View();
};


//dma.cpp
#include"dma.h"
#pragma warning(disable :4996)
using std::cout;
using std::endl;
base::base(const char* l, int r) :rating(r) {
	label = new char[std::strlen(l) + 1];
	strcpy(label, l);
}
base::base(const base& b) :rating(b.rating) {
	label = new char[std::strlen(b.label) + 1];
	strcpy(label, b.label);
}
base::~base() {
	delete[]label;
}
base& base::operator=(const base& b) {
	if (this == &b)
		return *this;
	delete[]label;
	label = new char[std::strlen(b.label) + 1];
	strcpy(label, b.label);
	rating = b.rating;
	return *this;
}
void base::View() {
	cout << "label: " << label << endl;
	cout << "rating: " << rating << endl;
}
/
baseDMA::baseDMA(const char* l, int r) :base(l, r) {}
baseDMA::~baseDMA() {}
void baseDMA::View() { base::View(); }
/
lacksDMA::lacksDMA(const char* c, const char* l, int r) : base(l, r) {
	strcpy_s(color, c);
}
lacksDMA::lacksDMA(const char* c, const base& b) : base(b) {
	std::strcpy(color, c);
}
lacksDMA::~lacksDMA() {}
void lacksDMA::View() {
	base::View();
	cout << "color: " << color << endl;
}
/
hasDMA::hasDMA(const char* s, const char* l, int r) :base(l, r) {
	style = new char[std::strlen(s) + 1];
	strcpy_s(style, std::strlen(s) + 1, s);
}
hasDMA::hasDMA(const char* s, const base& b) : base(b) {
	style = new char[std::strlen(s) + 1];
	strcpy_s(style, std::strlen(s) + 1, s);
}
hasDMA::hasDMA(const hasDMA& hd) : base(hd) {
	style=new char[std::strlen(hd.style) + 1];
	strcpy_s(style, std::strlen(hd.style) + 1, hd.style);
}
hasDMA::~hasDMA() {
	delete[]style;
}
hasDMA& hasDMA::operator=(hasDMA& hd) {
	if (this == &hd)
		return *this;
	base::operator=(hd);
	delete[]style;
	style = new char[std::strlen(hd.style) + 1];
	strcpy_s(style, std::strlen(hd.style) + 1, hd.style);
	return *this;
}
void hasDMA::View() {
	base::View();
	cout << "style: " << style << endl;
}



//main.cpp
#include<iostream>
#include"dma.h"
using namespace std;
int main() {
	base* pbase[4];
	char label[40];
	int rating = 0;
	char color[40];
	char style[40];
	char kind;

	for (int i = 0; i < 4; i++) {
		cout << "Enter label:";
		cin.getline(label, 40);
		cout << "Enter rating:";
		cin >> rating;
		cout << "Enter 1 for baseDMA, 2 for lacksDMA, 3 for hasDMA:";
		while (cin >> kind && (kind != '1' && kind != '2' && kind != '3'))
			cout << "Enter either 1,2 or 3:";
		cin.get();
		if (kind == '1')
			pbase[i] = new baseDMA(label, rating);
		else if (kind == '2') {
			cout << "Enter color:";
			cin.getline(color, 40);
			pbase[i] = new lacksDMA(color, label, rating);
		}
		else {
			cout << "Enter style:";
			cin.getline(style, 40);
			pbase[i] = new hasDMA(style, label, rating);
		}

	}
	cout << endl;
	for (int i = 0; i < 4; i++) {
		pbase[i]->View();
		cout << endl;
	}
	for (int i = 0; i < 4; i++)
		delete pbase[i];
	cout << "Done!\n";
	return 0;
}

practice 4

c.赋值运算符和友元函数是无法继承的,也不需要重新定义,而是每个类各自编写,
每个类都只会使用自己的operator=()(赋值运算符)和operator<<()(友元函
数),因此也就不需要声明为虚函数

b.首先构造函数和Show()因为有了新成员需要重新定义,析构函数,复制构造函数,
赋值运算符因为使用了char*指针,需要用new[]分配内存,所以三者都要重新定义,
+=和-=运算符重载,它们对两个类的行为都是一样的,不需要重新定义
//port.h
#pragma once
#include<iostream>
using namespace std;
class Port {
	char* brand;
	char style[20];
	int bottles;
public:
	Port(const char* br = "none", const char* st = "none", int b = 0);
	Port(const Port& p);
	virtual~Port() { delete[]brand; }
	Port& operator=(const Port& p);
	Port& operator+=(int b);
	Port& operator-=(int b);
	int BattleCount() { return bottles; }
	virtual void Show()const;
	friend ostream& operator<<(ostream& os, const Port& p);
};
class VintagePort :public Port {
	char* nickname;
	int year;
public:
	VintagePort();
	VintagePort(const char* br, const char* st, int b, const char* nn, int y);
	VintagePort(const VintagePort& vp);
	~VintagePort() { delete[]nickname; }
	VintagePort& operator=(const VintagePort& vp);
	void Show()const;
	friend ostream& operator<<(ostream& os, const VintagePort& vp);
};


//port.cpp
#include"port.h"
Port::Port(const char* br = "none", const char* st = "none", int b = 0) : bottles(b) {
	brand = new char[strlen(br) + 1];
	strcpy_s(brand, strlen(br) + 1, br);
	strcpy_s(style, st);
}
Port::Port(const Port& p) {
	brand = new char[strlen(p.brand) + 1];
	strcpy_s(brand, strlen(p.brand) + 1, p.brand);
	strcpy_s(style, p.style);
	bottles = p.bottles;
}
Port& Port::operator=(const Port& p) {
	if (this == &p)
		return *this;
	delete[]brand;
	strcpy_s(brand, strlen(p.brand) + 1, p.brand);
	strcpy_s(style, p.style);
	bottles = p.bottles;
}
Port& Port::operator+=(int b) {
	bottles += b;
	return *this;
}
Port& Port::operator-=(int b) {
	bottles -= b;
	return *this;
}
void Port::Show()const {
	cout << "Brand: " << brand << endl;
	cout << "Style: " << style << endl;
	cout << "Bottles: " << bottles << endl;
}
ostream& operator<<(ostream& os, const Port& p) {
	os << p.brand << " " << p.style << " " << p.bottles << " ";
}

VintagePort::VintagePort() :Port() {
	nickname = nullptr;
	year = 0;
}
VintagePort::VintagePort(const char* br, const char* st, int b, const char* nn, int y)
	: Port(br, st, b), year(y) {
	nickname = new char[strlen(nn) + 1];
	strcpy_s(nickname, strlen(nn) + 1, nn);
}
VintagePort::VintagePort(const VintagePort& vp) : Port(vp), year(vp.year) {
	nickname = new char[strlen(vp.nickname) + 1];
	strcpy_s(nickname, strlen(vp.nickname) + 1, vp.nickname);
}
VintagePort& VintagePort::operator=(const VintagePort& vp) {
	if (this == &vp)
		return *this;
	Port::operator=(vp);
	delete[]nickname;
	nickname = new char[strlen(vp.nickname) + 1];
	strcpy_s(nickname, strlen(vp.nickname) + 1, vp.nickname);
	year = vp.year;
	return *this;
}
void VintagePort::Show()const {
	Port::Show();
	cout << "Nickname: " << nickname << endl;
	cout << "Year: " << year << endl;
}
ostream& operator<<(ostream& os, const VintagePort& vp) {
	os << (const Port&)vp;
	os << vp.nickname << " " << vp.year << " ";
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值