第十四章编程练习

1.Wine类有一个string类对象成员(参见第4章)和一个Pair对象(参见本章);其中前者用于存储葡萄酒的名称,而后者有2个valarray<int>对象(参见本章),这两个valarray<int>对象可能为1988、1992和1996年,第二个valarray<int>对象可能为24、48和144瓶。Wine最好有1个int成员用于存储年数。另外,一些typedef可能有助于简化编程工作:

typedef std::valarray<int> ArrayInt;
typedef Pair<ArrayInt, ArrayInt> PairArray;

这样,PairArray表示的是类型Pairstd::valarray<int>std::valarray<int>。使用包含来实现Wine类,并用一个简单的程序对其进行测试。Wine类应该有一个默认构造函数以及如下构造函数:

// initialize label to l, number of years to y,
// vintage years to yr[], bottles to bot[]
Wine(const char * l, int y, const int yr[], const int bot[]);
// initialize label to l, number of years to y,
// create array objects of length y
Wine(const char * l, int y);

Wine类应该有一个GetBottles()方法,它根据Wine对象能够存储几种年份(y),提示用户输入年份和瓶数。方法Label()返回一个指向葡萄酒名称的引用。sum()方法返回Pair对象中第二个valarray<int>对象中的瓶数总和。
测试程序应提示用户输入葡萄酒名称、元素个数以及每个元素存储的年份和瓶数等信息。程序将使用这些数据来构造一个Wine对象,然后显示对象中保存的信息。
下面是一个简单的测试程序:

#include <iostream>
#include "winec.h"

int main ( void )
{
    using std::cin;
    using std::cout;
    using std::endl;

    cout << "Enter name of wine: ";
    char lab[50];
    cin.getline(lab, 50);
    cout << "Enter number of years: ";
    int yrs;
    cin >> yrs;

    Wine holding(lab, yrs); // store label, years, give arrays yrs elements
    holding.GetBottles();   // solicit input for year, bottle count
    holding.Show();         // display object contents

    const int YRS = 3;
    int y[YRS] = {1993, 1995, 1998};
    int b[YRS] = { 48, 60, 72};
    // create new object, initialize using data in arrays y and b
    Wine more("Gushing Grape Red",YRS, y, b);
    more.Show();
    cout << "Total bottles for " << more.Label() // use Label() method
         << ": " << more.sum() << endl;          // use sum() method
    cout << "Bye\n";
    return 0;
}

实现:
winec.h

#pragma once
#include <iostream>
#include <string>
#include <valarray>
using namespace std;


template<class T1, class T2> class Pair;//前置声明

typedef valarray<int> ArrayInt;
typedef Pair<ArrayInt, ArrayInt> PairArray;

template<class T1, class T2>//模板类
class Pair
{
private:
	T1 a;
	T2 b;
public:
	Pair(const T1& aval, const T2& bval) : a(aval), b(bval) {}
	T1& first();
	T2& second();
	T1 first() const { return a; }
	T2 second() const { return b; }
};

//Wine Class
class Wine
{
private:
	string m_label;//葡萄酒名称
	//Pair<valarray<int>, valarray<int>> m_info;//实例化Pair
	//Pair <ArrayInt, ArrayInt> m_info;
	PairArray m_info;//葡萄酒具体哪一年和哪一年的瓶数
	int m_year;//几个年份
public:
	Wine(const char* l, int y, const int yr[], const int bot[]);
	Wine(const char* l, int y);
	void GetBottles();
	const string& GetLabel() const;
	int SumBottles() const;
	void ShowInfo();
};

template<class T1, class T2>
T1& Pair<T1, T2>::first()
{
	return a;
}

template<class T1, class T2>
T2& Pair<T1, T2>::second()
{
	return b;
}

winec.cpp

#include "winec.h"

Wine::Wine(const char* l, int y, const int yr[], const int bot[]) : m_label(l), m_year(y),m_info(ArrayInt(yr,y), ArrayInt(bot,y))
{
}

Wine::Wine(const char* l, int y) : m_label(l), m_year(y), m_info(ArrayInt(0,0), ArrayInt(0,0))
{
}

void Wine::GetBottles()
{
	cout << "Enter " << m_label << " data for " << m_year << endl;
	ArrayInt a(m_year);
	ArrayInt b(m_year); 
	for (int i = 0; i < m_year; i++)
	{
		cout << "Enter year: ";
		cin >> a[i];
		cout << "Enter bottles for thar year: ";
		cin >> b[i];
	}
	m_info.first() = std::move(a);
	m_info.second() = move(b);
}

const string& Wine::GetLabel() const
{
	return m_label;
}

int Wine::SumBottles() const
{
	return m_info.second().sum();
}

void Wine::ShowInfo()
{
	cout << "Wine: " << m_label << endl;
	cout << "		Year		Bottles" << endl;
	for (int i = 0; i < m_year; i++)
	{
		cout << "		" << m_info.first()[i] << "		" << m_info.second()[i] << endl;

	}
}

2.采用私有继承而不是包含来完成编程编程练习1。同样,一些typedef可能会有所帮助,另外,您可能还需要考虑诸如下面这样的语句的定义:

PairArray::operator=(PairArray(ArrayInt(),ArrayInt()));
cout << (const string &)(*this);

您设计的类应该可以使用编程练习1中的测试程序进行测试。
实现:
wine.h

#pragma once
#include <iostream>
#include <string>
#include <valarray>
using namespace std;


template<class T1, class T2> class Pair;//前置声明

typedef valarray<int> ArrayInt;
typedef Pair<ArrayInt, ArrayInt> PairArray;

template<class T1, class T2>//模板类
class Pair
{
private:
	T1 a;
	T2 b;
public:
	Pair(const T1& aval, const T2& bval) : a(aval), b(bval) {}
	T1& first();
	T2& second();
	T1 first() const { return a; }
	T2 second() const { return b; }
};

//Wine Class
class Wine : private string, private PairArray
{
private:
	//string m_label;//葡萄酒名称
	//Pair<valarray<int>, valarray<int>> m_info;//实例化Pair
	//Pair <ArrayInt, ArrayInt> m_info;
	//PairArray m_info;//葡萄酒具体哪一年和哪一年的瓶数
	int m_year;//几个年份
public:
	Wine(const char* l, int y, const int yr[], const int bot[]);
	Wine(const char* l, int y);
	void GetBottles();
	const string& GetLabel() const;
	int SumBottles() const;
	void ShowInfo();
};

template<class T1, class T2>
T1& Pair<T1, T2>::first()
{
	return a;
}

template<class T1, class T2>
T2& Pair<T1, T2>::second()
{
	return b;
}

wine.cpp

#include "winec2.h"

Wine::Wine(const char* l, int y, const int yr[], const int bot[]) : string(l), m_year(y), PairArray(ArrayInt(yr, y), ArrayInt(bot, y))
{
}

Wine::Wine(const char* l, int y) : string(l), m_year(y), PairArray(ArrayInt(0, 0), ArrayInt(0, 0))
{
}

void Wine::GetBottles()
{
	cout << "Enter " << (const string&)*this << " data for " << m_year << endl;
	ArrayInt a(m_year);
	ArrayInt b(m_year);
	for (int i = 0; i < m_year; i++)
	{
		cout << "Enter year: ";
		cin >> a[i];
		cout << "Enter bottles for thar year: ";
		cin >> b[i];
	}
	PairArray::first() = std::move(a);
	PairArray::second() = move(b);
}

const string& Wine::GetLabel() const
{
	return (const string&)*this;
}

int Wine::SumBottles() const
{
	return PairArray::second().sum();
}

void Wine::ShowInfo()
{
	cout << "Wine: " << (const string&)*this << endl;
	cout << "		Year		Bottles" << endl;
	for (int i = 0; i < m_year; i++)
	{
		cout << "		" << PairArray::first()[i] << "		" << PairArray::second()[i] << endl;

	}
}

3.定义一个QueueTp模板。然后在一个类似于程序清单14.12的程序中创建一个指向Worker的指针队列(参见程序清单14.10中的定义),并用该队列来测试它。
实现:
queue.h

#pragma once

#include <iostream>
#include <string>
using namespace std;


//Worker class
class Worker
{
private:
	string fullname;
	long id;
public:
	Worker() :fullname("none one"), id(0){}
	Worker(const string& s, long n) :fullname(s), id(n){}
	~Worker(){}
	void Set();
	void Show() const;
};


//Queue Template
template<class T>
class Queue
{
private:
	enum{Q_SIZE = 10};
	struct Node 
	{ 
		T item;
		struct Node* next;
	};
	Node* front;
	Node* rear;
	int items;
	const int qsize;
public:
	Queue(int qs = Q_SIZE);
	~Queue();
	bool isempty()const;
	bool isfull()const;
	int queuecount()const;
	bool enqueue(const T& item);
	bool dequeue(T& item);
};

template<class T>
Queue<T>::Queue(int qs):qsize(qs)
{
	front = rear = nullptr;
	items = 0;
}

template<class T>
Queue<T>::~Queue()
{
	Node* temp;
	if (front != NULL)
	{
		temp = front;
		front = front->next;
		delete temp;
	}
}

template<class T>
bool Queue<T>::isempty() const
{
	return items == 0;
}

template<class T>
inline bool Queue<T>::isfull() const
{
	return items == qsize;
}

template<class T>
int Queue<T>::queuecount() const
{
	return items;
}

template<class T>
bool Queue<T>::enqueue(const T& item)
{
	if (isfull())
	{
		return false;
	}

	Node* add = new Node;
	add->item = item;
	add->next = nullptr;
	items++;

	if (front == nullptr)
	{
		front = add;
	}
	else
	{
		rear->next = add;
	}
	rear = add;
	return true;
}

template<class T>
bool Queue<T>::dequeue(T& item)
{
	if (front == nullptr)
	{
		return false;
	}
	item = front->item;
	items--;
	Node* temp = front;
	front = front->next;
	delete temp;
	if (items == 0)
	{
		rear = nullptr;
	}
	return true;
}

queue.cpp

#include "queue.h"

//Worker methods
void Worker::Set()
{
	cout << "Enter worker's fullname:";
	getline(cin, fullname);
	cout << "Enter worker's ID:";
	while (cin.get() != '\n');
}

void Worker::Show() const
{
	cout << "Name:" << fullname << endl;
	cout << "Employee ID:" << id << endl;
}

main.cpp

#include "queue.h"

int main(void)
{
	Queue<Worker* > wk(3);//3个Worker*
	Worker w1;
	w1.Set();
	w1.Show();
	wk.enqueue(&w1);
	cout << "Now queue has:" << wk.queuecount() << " objects." << endl;

	Worker w2;
	w2.Set();
	w2.Show();
	wk.enqueue(&w2);
	cout << "Now queue has:" << wk.queuecount() << " objects." << endl;

	Worker w3;
	w3.Set();
	w3.Show();
	wk.enqueue(&w3);
	cout << "Now queue has:" << wk.queuecount() << " objects." << endl;

	return 0;
}

4.Person类保存人的名和姓。除构造函数外,它还有Show()方法,用于显示名和姓。Gunsliger类以Person类为虚基类派生而来,它包含一个Dram()成员,该方法返回一个double值,表示枪手的拔枪时间。这个类还包含一个int成员,表示枪手枪上的刻痕数。最后,这个类还包含一个Show()函数,用于显示所有信息。
PokerPlayer类以Person类为虚基类派生而来。它包含一个Draw()成员,该函数返回一个1~52的随机数,用于表示扑克牌的值(也可以定义一个Card类,其中包含花色和面值成员,然后让Draw()返回一个Card对象)。PokerPlayer类使用Person类的show()函数。BadDude()类从Gunsliger和PokerPlayer类公有派生而来。它包含Gdraw()成员(返回坏蛋拔枪的时间)和Cdraw()成员(返回下一张扑克牌),另外还有一个合适的Show()函数。请定义这些类和方法以及其他必要的方法(如用于设置对象值的方法),并使用一个类似于程序清单14.12的简单程序对它们进行测试。
实现:

//无

5.下面是一些类声明:

//emp.h
#pragma once

#include<iostream>
#include<string>
using std::string;
using std::ostream;
using std::cout;
using std::endl;
using std::cin;
//using std::getline;

class abstr_emp
{
private:
	string fname;
	string lname;
	string job;
public:
	abstr_emp();
	abstr_emp(const string& fn, const string& ln, const string& j);
	virtual void ShowAll() const;
	virtual void SetAll();
	friend ostream& operator<<(ostream& os, const abstr_emp& e);
	virtual ~abstr_emp() = 0;//纯虚函数
};

class employee : public abstr_emp
{
public:
	employee();
	employee(const string& fn, const string& ln, const string& j);
	virtual void ShowAll()const;
	virtual void SetAll();
};

class manager : virtual public abstr_emp
{
private:
	int inchargeof;
protected:
	int InChargeOf() const { return inchargeof; }
	int& InChargeOf() { return inchargeof; }
public:
	manager();
	manager(const string& fn, const string& ln, const string& j, int ico = 0);
	manager(const abstr_emp& e, int ico);
	manager(const manager& m);
	virtual void ShowAll()const;
	virtual void SetAll();
};

class fink : virtual public abstr_emp
{
private:
	string reportsto;
protected:
	const string ReportsTo()const { return reportsto; }
	string& ReportsTo() { return reportsto; }
public:
	fink();
	fink(const string& fn, const string& ln, const string& j, const string& rpo);
	fink(const abstr_emp& e, const string& rpo);
	fink(const fink& e);
	virtual void ShowAll()const;
	virtual void SetAll();
};

class highfink : public manager, public fink
{
public:
	highfink();
	highfink(const string& fn, const string& ln, const string& j, const string& rpo, int ico);
	highfink(const abstr_emp& e, const string& rpo, int ico);
	highfink(const fink& f, int ico);
	highfink(const manager& m, const string& rpo);
	highfink(const highfink& h);
	virtual void ShowAll()const;
	virtual void SetAll();
};

注意,该类层次结构使用了带虚基类的MI,所以要牢记在这种情况下用于构造函数初始化列表的特殊规则。还需要注意的是,有些方法被声明为保护的。这可以简化一些highfink方法的代码(例如,如果highfink::ShowAll()只是调用fink::ShowAll()和manager::ShowAll(),则它将调用abstr_emp::ShowAll()两次)。请提供类方法的实现,并在一个程序中对这些类进行测试。下面是一个小型测试程序:
实现:
emp.cpp

#include "emp.h"

//abstr_emp methods
abstr_emp::abstr_emp():fname("none"), lname("none"),job("none")
{
}

abstr_emp::abstr_emp(const string& fn, const string& ln, const string& j) : fname(fn), lname(ln),job(j)
{
}

void abstr_emp::ShowAll() const
{
	cout << "fname:" << fname << endl;
	cout << "lname:" << lname << endl;
	cout << "job:" << job << endl;
}

void abstr_emp::SetAll()
{
	cout << "Enter the first name:";
	getline(cin, fname);
	cout << "Enter the last name:";
	getline(cin, lname);
	cout << "Enter the job:";
	getline(cin, job);
}

abstr_emp::~abstr_emp()
{
}

ostream& operator<<(ostream& os, const abstr_emp& e)
{
	os << "fname:" << e.fname << endl;
	os << "lname:" << e.lname << endl;
	os << "job:" << e.job << endl;
	return os;
}

//employee methods
employee::employee() : abstr_emp()
{
}

employee::employee(const string& fn, const string& ln, const string& j) : abstr_emp(fn,ln,j)
{

}

void employee::ShowAll() const
{
	abstr_emp::ShowAll();
}

void employee::SetAll()
{
	abstr_emp::SetAll();
}

//manager methods
manager::manager() : abstr_emp(),inchargeof(0)
{
}

manager::manager(const string& fn, const string& ln, const string& j, int ico) : abstr_emp(fn, ln, j),inchargeof(ico)
{
}

manager::manager(const abstr_emp& e, int ico) : abstr_emp(e), inchargeof(ico)
{
}

manager::manager(const manager& m) : abstr_emp(m)
{
	inchargeof = m.inchargeof;
}

void manager::ShowAll() const
{
	abstr_emp::ShowAll();
	cout << "ico:" << inchargeof << endl;
}

void manager::SetAll()
{
	abstr_emp::SetAll();
	cout << "ico:";
	cin >> inchargeof;
}

//fink methods
fink::fink() : abstr_emp(), reportsto("none")
{
}

fink::fink(const string& fn, const string& ln, const string& j, const string& rpo): abstr_emp(fn, ln, j), reportsto(rpo)
{
}

fink::fink(const abstr_emp& e, const string& rpo): abstr_emp(e), reportsto(rpo)
{
}

fink::fink(const fink& e):abstr_emp(e)
{
	reportsto = e.reportsto;
}

void fink::ShowAll() const
{
	abstr_emp::ShowAll();
	cout << "reportsto:" << reportsto << endl;
}

void fink::SetAll()
{
	abstr_emp::SetAll();
	cout << "reportsto:";
	cin >> reportsto;
}

//highfink methods
highfink::highfink() : abstr_emp(),manager(),fink()
{
}

highfink::highfink(const string& fn, const string& ln, const string& j, const string& rpo, int ico) : abstr_emp(fn,ln,j), manager(fn,ln, j,ico), fink(fn,ln,j,rpo)
{
}

highfink::highfink(const abstr_emp& e, const string& rpo, int ico) : abstr_emp(e), manager(e,ico), fink(e,rpo)
{
}

highfink::highfink(const fink& f, int ico): abstr_emp(f),manager(f,ico),fink(f)
{
}

highfink::highfink(const manager& m, const string& rpo): abstr_emp(m),manager(m),fink(m,rpo)
{
}

highfink::highfink(const highfink& h): abstr_emp(h), manager(h),fink(h)
{
}

void highfink::ShowAll() const
{
	fink::ShowAll();
	manager::ShowAll();
}

void highfink::SetAll()
{
	fink::SetAll();
	manager::SetAll();
}

main.cpp

#include "emp.h"


int main(void)
{
    employee em("Trip", "Harris", "Thumper");
    cout << em << endl;
    em.ShowAll();
    manager ma("Amorphia", "Spindragon", "Nuancer", 5);
    cout << ma << endl;
    ma.ShowAll();

    fink fi("Matt", "Oggs", "Oiler", "Juno Barr");
    cout << fi << endl;
    fi.ShowAll();
    highfink hf(ma, "Curly Kew"); // recruitment?
    hf.ShowAll();
    cout << "Press a key for next phase:\n";
    cin.get();
    highfink hf2;
    hf2.SetAll();

    cout << "Using an abstr_emp * pointer:\n";
    abstr_emp* tri[4] = { &em, &fi, &hf, &hf2 };
    for (int i = 0; i < 4; i++)
        tri[i]->ShowAll();

	return 0;
}

问题:
1.为什么没有定义赋值运算符?
答:没使用动态内存分配;成员都是string类型,有赋值运算符重载函数。
2.为什么要将ShowAll()和SetAll()定义为虚的?
答:不同的派生类里都有ShowAll()SetAll()实现,实现的方法不一样,为了实际使用的对象去调用正确的ShowAll()SetAll()方法。
3.为什么要将abstr_emp定义为虚基类?
答:虚基类使得从多个类派生出的对象只继承一个基类对象,如果不把abstr_emp定义为虚基类,highfink类对象里会存在2个abstr_emp的副本,既占用内存空间又容易冲突。
4.为什么highfink类没有数据成分?
答:完全继承了manager和fink里的私有成员,足够去描述highfink的成分。
5.为什么只需要一个operator<<()版本?
答:派生出的类都有ShowAll()方法,没必要再去定义operator<<。

如果使用下面的代码替换程序的结尾部分,将会发生什么情况?

abstr_emp tri[4] = {em, fi, hf, hf2};
for (int i = 0; i < 4; i++)
      tri[i].ShowAll();

答:编译报错,抽象基类abstr_emp无法创建对象或对象数组。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值