当前位置:嗨网首页>书籍在线阅读

28-编程练习

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

14.7 编程练习

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

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

这样,PairArray表示的是类型Pair<std::valarray, std::valarray >。使用包含来实现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对象中的瓶数总和。

测试程序应提示用户输入葡萄酒名称、元素个数以及每个元素存储的年份和瓶数等信息。程序将使用这些数据来构造一个Wine对象,然后显示对象中保存的信息。

下面是一个简单的测试程序:

// pe14-1.cpp -- using Wine class with containment
#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;
}

下面是该程序的运行情况:

Enter name of wine: Gully Wash
Enter number of years: 4
Enter Gully Wash data for 4 year(s):
Enter year: 1988
Enter bottles for that year: 42
Enter year: 1994
Enter bottles for that year: 58
Enter year: 1998
Enter bottles for that year: 122
Enter year: 2001
Enter bottles for that year: 144
Wine: Gully Wash
        Year    Bottles
        1988    42
        1994    58
        1998    122
        2001    144
Wine: Gushing Grape Red
        Year    Bottles
        1993    48
        1995    60
        1998    72
Total bottles for Gushing Grape Red: 180
Bye

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

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

您设计的类应该可以使用编程练习1中的测试程序进行测试。

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

4.Person类保存人的名和姓。除构造函数外,它还有Show()方法,用于显示名和姓。Gunslinger类以Person类为虚基类派生而来,它包含一个Draw()成员,该方法返回一个double值,表示枪手的拔枪时间。这个类还包含一个int成员,表示枪手枪上的刻痕数。最后,这个类还包含一个Show()函数,用于显示所有这些信息。

PokerPlayer类以Person类为虚基类派生而来。它包含一个Draw()成员,该函数返回一个1~52的随机数,用于表示扑克牌的值(也可以定义一个Card类,其中包含花色和面值成员,然后让Draw()返回一个Card对象)。PokerPlayer类使用Person类的show()函数。BadDude()类从Gunslinger和PokerPlayer类公有派生而来。它包含Gdraw()成员(返回坏蛋拔枪的时间)和Cdraw()成员(返回下一张扑克牌),另外还有一个合适的Show()函数。请定义这些类和方法以及其他必要的方法(如用于设置对象值的方法),并使用一个类似于程序清单14.12的简单程序对它们进行测试。

5.下面是一些类声明:

// emp.h -- header file for abstr_emp class and children
#include <iostream>
#include <string>
class abstr_emp
{
private:
    std::string fname;   // abstr_emp's first name
    std::string lname;   // abstr_emp's last name
    std::string job;
public:
    abstr_emp();
    abstr_emp(const std::string & fn, const std::string & ln,
             const std::string & j);
    virtual void ShowAll() const; // labels and shows all data
    virtual void SetAll();        // prompts user for values
    friend std::ostream &
             operator<<(std::ostream & os, const abstr_emp & e);
    // just displays first and last name
    virtual ~abstr_emp() = 0;     // virtual base class
};
class employee : public abstr_emp
{
public:
    employee();
    employee(const std::string & fn, const std::string & ln,
             const std::string & j);
    virtual void ShowAll() const;
    virtual void SetAll();
};
class manager: virtual public abstr_emp
{
private:
    int inchargeof; // number of abstr_emps managed
protected:
    int InChargeOf() const { return inchargeof; } // output
    int & InChargeOf(){ return inchargeof; }      // input
public:
    manager();
    manager(const std::string & fn, const std::string & ln,
            const std::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:
    std::string reportsto; // to whom fink reports
protected:
    const std::string ReportsTo() const { return reportsto; }
    std::string & ReportsTo(){ return reportsto; }
public:
    fink();
    fink(const std::string & fn, const std::string & ln,
         const std::string & j, const std::string & rpo);
    fink(const abstr_emp & e, const std::string & rpo);
    fink(const fink & e);
    virtual void ShowAll() const;
    virtual void SetAll();
};
class highfink: public manager, public fink // management fink
{
public:
    highfink();
    highfink(const std::string & fn, const std::string & ln,
             const std::string & j, const std::string & rpo,
             int ico);
    highfink(const abstr_emp & e, const std::string & rpo, int ico);
    highfink(const fink & f, int ico);
    highfink(const manager & m, const std::string & rpo);
    highfink(const highfink & h);
    virtual void ShowAll() const;
    virtual void SetAll();
};

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

// pe14-5.cpp
// useemp1.cpp -- using the abstr_emp classes
#include <iostream>
using namespace std;
#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;
}

为什么没有定义赋值运算符?

为什么要将ShowAll()和SetAll()定义为虚的?

为什么要将abstr_emp定义为虚基类?

为什么highfink类没有数据部分?

为什么只需要一个operator<<()版本?

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

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