欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2023-12-22 23:10:04
...

复习题

//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 << " ";
}

相关标签: c++

上一篇:

下一篇: