C++ Primer Plus(第 6 版)第十至十八章课后习题答案

转载公众号: iDoitnow 用于学习笔记使用。

目录

 

第十章课后习题答案 

复习题

编程练习

 第十一章课后习题答案

复习题

编程练习

 第十二章课后习题答案

复习题

编程练习

第十三章课后习题答案

复习题

编程练习

第十四章课后习题答案

复习题

编程练习

第十五章课后习题答案

复习题

编程练习

第十六章课后习题答案

 复习题

编程练习

第十七章课后习题答案

复习题

 编程练习

第十八章课后习题答案

复习题

编程练习

 

第十章课后习题答案 

复习题

1.什么是类?

类是用户定义的类型的定义。类声明指定了数据将如何存储,同时提供了访问和操作这些数据的方法。

2.类如何实现抽象、封装和数据隐藏?

用户可以根据类的公有接口对类对象执行的操作,这是抽象。类的数据成员可以是私有的(默认值),这意味着只能通过类成员函数来对数据进行访问,这是数据隐藏。实现的具体细节(如数据的表示和方法的代码)都是隐藏的,这是封装。

3.对象和类之间的关系是什么?

类定义了一种类型,包括如何使用它。对象是一个变量或其他的数据对象(如new生成的),并根据类定义被创建和使用。类和对象之间的关系同标准类型与其变量之间的关系。

4.除了是函数之外,类函数成员与类数据成员之间的区别是什么?

如果创建给定类的多个对象,则每个对象都有其自己的数据内存空间;但所有的对象都使用同一组成员函数(通常,这个方法是公有的,而数据是私有的,但这只是策略方面的问题,而不是对类的要求)

5.定义一个类来表示银行账户、数据成员包括储户姓名、帐号(使用字符串)和存款。成员函数执行如下操作:

  • 创建一个对象并将其初始化。

  • 显示储户姓名、帐号和存款。

  • 存入参数指定的存款。

  • 取出参数指定的款项。

请提供类声明,而不用给出方法实现。(编程练习1将要求编写实现)

#ifndef BANKACCOUNT_H
#define BANKACCOUNT_H
#include <string>

using namespace std;

class BankAccount
{
private:
    std::string name_str;
    std::string accountNum_str;
    double balance;

public:
    BankAccount(const string &name, const string &accountNum, double bal = 0.0);
    void show();
    void deposit(double cash);
    void withdraw(double cash);
};

#endif

6.类构造函数在何时被调用?类析构函数呢?

在创建类对象或显示调用构造函数时,类的构造函数被调用。当函数过期时,析构函数被调用。

7.给出复习题5中的银行账户的构造函数的代码。

#include "BankAccount.h"
#include <iostream>
using namespace std;

BankAccount::BankAccount(const string &name, const string &accountNum, double bal)
{
    name_str = name;
    accountNum_str = accountNum;
    balance = bal;
}

void BankAccount::show()
{
    cout << "Account Name : " << name_str << endl;
    cout << "Account Number : " << accountNum_str << endl;
    cout << "Account Balance : " << balance << endl;
}

void BankAccount::withdraw(double cash)
{
    balance -= cash;
}

void BankAccount::deposit(double cash)
{
    balance += cash;
}

8.什么是默认构造函数,拥有默认构造函数有何好处?

默认构造函数是没有参数或所有参数都有默认值的构造函数。拥有默认构造函数后,可以声明对象,而不初始化它,即使已经定义了初始化构造函数。它还使得能够声明数组。

9.修改Stock类的定义(stock20.h中的版本),使之包含返回各个数据成员值的成员函数。注意:返回公司名的成员函数不应该为修改数组提供便利,也就是说,不能简单的返回string引用。

原stock20.h的版本:

//Listing 10.7 stock20.h
// stock20.h -- augmented version
#ifndef STOCK20_H_
#define STOCK20_H_
#include <string>
class Stock
{
private:
    std::string company;
    int shares;
    double share_val;
    double total_val;
    void set_tot() { total_val = shares * share_val; }

public:
    Stock(); // default constructor
    Stock(const std::string &co, long n = 0, double pr = 0.0);
    ~Stock(); // do-nothing destructor
    void buy(long num, double price);
    void sell(long num, double price);
    void update(double price);
    void show() const;
    const Stock &topval(const Stock &s) const;
};
#endif

修改后:

#ifndef STOCK20_H_
#define STOCK20_H_
#include <string>
class Stock
{
private:
    std::string company;
    int shares;
    double share_val;
    double total_val;
    void set_tot() { total_val = shares * share_val; }

public:
    Stock();
    Stock(const std::string &co, long n = 0, double pr = 0.0);
    ~Stock();
    void buy(long num, double price);
    void sell(long num, double price);
    void update(double price);
    void show() const;
    const Stock &topval(const Stock &s) const;
    int shares() const { return shares; }
    double shareVal() const { return share_val; }
    double totalVal() const { return total_val; }
    const std::string &comp_name() const { return company; }
};
#endif

10.this和*this是什么?

this指针是类方法可以使用的指针,它指向用于调用方法的对象。因此,this是对象的地址,*this是对象本身。

编程练习

1.为复习题5描述的类提供方法定义,并编写一个小程序来演示所有的特性。

BankAccount.h:

#ifndef BANKACCOUNT_H
#define BANKACCOUNT_H
#include <string>

using namespace std;

class BankAccount
{
private:
    std::string name_str;
    std::string accountNum_str;
    double balance;

public:
    BankAccount(const string &name, const string &accountNum, double bal = 0.0);
    void show();
    void deposit(double cash);
    void withdraw(double cash);
};

#endif

BankAccount.cpp:

#include "BankAccount.h"
#include <iostream>
using namespace std;

BankAccount::BankAccount(const string &name, const string &accountNum, double bal)
{
    name_str = name;
    accountNum_str = accountNum;
    balance = bal;
}

void BankAccount::show()
{
    cout << "Account Name : " << name_str << endl;
    cout << "Account Number : " << accountNum_str << endl;
    cout << "Account Balance : " << balance << endl;
}

void BankAccount::withdraw(double cash)
{
    balance -= cash;
}

void BankAccount::deposit(double cash)
{
    balance += cash;
}

main.cpp:

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

using namespace std;

int main()
{
    string name, account;
    double num;
    cout << "enter name : ";
    getline(cin, name);
    cout << "enter bank account : ";
    getline(cin, account);

    BankAccount ba(name, account);
    cout << "enter the deposit amount : ";
    cin >> num;
    cin.get();
    ba.deposit(num);
    cout << "your current bank account information : ";
    ba.show();

    cout << "enter the withdrawal amount: ";
    cin >> num;
    cin.get();
    ba.withdraw(num);
    cout << "your current bank account information : ";
    ba.show();

    return 0;
}

2. 下面是一个非常简单的类定义:

class Person
{
private:
    static const int LIMIT = 25;
    string lname;      // Person’s last name
    char fname[LIMIT]; // Person’s first name
public:
    Person()
    {
        lname = "";
        fname[0] = '\0';
    }                                                    // #1
    Person(const string &ln, const char *fn = "Heyyou"); // #2
    // the following methods display lname and fname
    void Show() const;       // firstname lastname format
    void FormalShow() const; // lastname, firstname format
};

它使用了一个string对象和一个字符数组,让您能够比较它们的用法。请提供未定义的方法的代码,以完成这个类的实现。再编写一个使用这个类的程序,它使用了三种可能的构造函数的调用(没有参数、一个参数和两个参数)以及两种显示方法。下面是一个使用这些构造函数和方法的例子:

Person one;                      // use default constructor
Person two("Smythecraft");       // use #2 with one default argument
Person three("Dimwiddy", "Sam"); // use #2, no defaults one.Show();
cout << endl;
one.FormalShow();
// etc. for two and three

Person.h :

#ifndef PERSON_H
#define PERSON_H

#include <string>
using std::string;

class Person
{
private:
    static const int LIMIT = 25;
    string lname;      // Person’s last name
    char fname[LIMIT]; // Person’s first name
public:
    Person()
    {
        lname = "";
        fname[0] = '\0';
    }                                                    // #1
    Person(const string &ln, const char *fn = "Heyyou"); // #2
    // the following methods display lname and fname
    void Show() const;       // firstname lastname format
    void FormalShow() const; // lastname, firstname format
};

#endif

Person.cpp :

#include "Person.h"
#include <iostream>
using std::cout;
using std::endl;

Person::Person(const string &ln, const char *fn)
{
    lname = ln;
    strcpy(fname, fn);
}

void Person::FormalShow() const
{
    cout << fname << " " << lname << endl;
}

void Person::Show() const
{
    cout << fname << " , " << lname << endl;
}

main.cpp :

#include "Person.h"
#include <iostream>
using std::cout;
using std::endl;
int main()
{
    Person one;
    Person two("Smythecraft");
    Person three("Dimwiddy", "Sam");
    cout << "Person one : " << endl;
    one.Show();
    one.FormalShow();
    cout << "Person two : " << endl;
    two.Show();
    two.FormalShow();
    cout << "Person two : " << endl;
    three.Show();
    three.FormalShow();
    return 0;
}

3.完成第9章的编程练习1,但要用正确的golf类声明替换那里的代码。用带合适参数的构造函数替换setgolf(golf &, const char * , int),以提供初始值。保留setgolf()的交互版本,但要用构造函数来实现它(例如,setgolf()的代码应该获得数据,将数据传递给构造函数来创建一个临时对象,并将其赋给调用对象,即*this)。

Golf.h:

#ifndef GOLF_H
#define GOLF_H

class Golf
{
public:
    Golf();
    Golf(const char *name, int hc);
    int setgolf();
    void sethandicap(int hc);
    void showgolf() const;

private:
    static const int Len = 40;
    char fullname[Len];
    int handicap;
};

#endif

Golf.cpp:

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

using namespace std;

Golf::Golf()
{
    strcpy(fullname, "DefaultName");
    handicap = 0;
}
Golf::Golf(const char *name, int hc)
{
    strcpy(fullname, name);
    handicap = hc;
}

int Golf::setgolf()
{
    cout << "please enter fullname : ";
    cin.getline(fullname, Len);
    if (strlen(fullname) == 0)
        return 0;
    else
    {
        cout << "please enter handicap : ";
        cin >> handicap;
        cin.get();
        return 1;
    }
}

void Golf::sethandicap(int hc)
{
    handicap = hc;
}

void Golf::showgolf() const
{
    cout << "fullname : " << fullname << ", handicap : " << handicap << endl;
}

main.cpp:

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

using namespace std;

int main()
{
    Golf ann("Ann Birdfree", 24), andy, arrGolf[3];
    ann.showgolf();

    andy.showgolf();
    andy.setgolf();
    andy.showgolf();
    andy.sethandicap(20);
    andy.showgolf();

    int i = 0;
    while (i < 3 && arrGolf[i].setgolf())
    {
        arrGolf[i].showgolf();
        i++;
        if (i < 3)
            cout << "next one: " << endl;
    }

    return 0;
}

4.完成第9章的编程练习4,但将Sales结构及相关的函数转换为一个类及其方法。用构造函数替换setSales(sales &,  double [], int)函数。用构造函数实现setSales(Slaes &)方法的交互版本。将类保留在名称空间SALES 中。

sales.h:

//sales.h-----头文件
#ifndef SALES_H
#define SALES_H

namespace SALES
{
    const int QUARTERS = 4;
    class Sales
    {
    public:
        Sales();
        Sales(const double ar[], int n);
        void showSales();

    private:
        double sales[QUARTERS];
        double average;
        double max;
        double min;
    };
}

#endif

sales.cpp:

//sales.cpp-----源代码文件
#include "sales.h"
#include <iostream>

using namespace std;
namespace SALES
{
    Sales::Sales(const double ar[], int n)
    {
        double min = 0, max = 0, sum = 0;
        min = max = ar[0];
        for (int i = 0; i < n; i++)
        {
            sales[i] = ar[i];
            sum += ar[i];
            if (ar[i] > max)
            {
                max = ar[i];
            }
            if (ar[i] < min)
            {
                min = ar[i];
            }
        }
        average = sum / n;
    }

    Sales::Sales()
    {
        cout << "Please enter 4 quarters for sales:" << endl;
        cout << "the 1 quarter :";
        cin >> sales[0];
        min = max = sales[0];
        for (int i = 1; i < 4; i++)
        {
            cout << "the " << i << " quarter :";
            cin >> sales[i];
            if (max < sales[i])
            {
                max = sales[i];
            }
            if (min > sales[i])
            {
                min = sales[i];
            }
        }
        average = (sales[0] + sales[1] + sales[2] + sales[3]) / 4;
    }

    void Sales::showSales()
    {
        cout << "Display all information in sales : " << endl;
        cout << "The 4 quarters are $" << sales[0] << ", $" << sales[1] << ", $" << sales[2] << ", $" << sales[3] << endl;
        cout << "The average income is $" << average << endl;
        cout << "The maximum income is $" << max << endl;
        cout << "The minimum income is $" << min << endl;
    }
}

main.cpp:

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

using namespace SALES;
int main()
{
    double arr[4] = {3.4, 5.6, 2.5, 6.1};
    Sales s1(arr, 4);
    s1.showSales();
    Sales s2;
    s2.showSales();
    return 0;
}

5.考虑下面的结构声明:

struct customer {
char fullname[35];
double payment;
};

编写一个程序,它从栈中添加和删除customer结构(栈用Stack类声明表示)。每次customer结构被删除时,其payment的值都被加入到总数中,并报告总数。注意:应该可以直接使用Stack类而不作修改;只需修改typedef声明,使Item的类型为customer,而不是unsigned long即可.

stack.h :

#ifndef STACK_H
#define STACK_H

struct customer
{
    char fullname[35];
    double payment;
};

typedef customer Item;

class Stack
{
public:
    Stack();
    bool pop(Item &it);
    bool push(const Item &it);
    bool isfull() const;
    bool isempty() const;

private:
    double total;
    int top;
    enum
    {
        MAX = 10
    };
    Item item[MAX];
};

#endif

stack.cpp :

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

using namespace std;

Stack::Stack()
{
    top = 0;
    total = 0;
}

bool Stack::isempty() const
{
    return top == 0;
}

bool Stack::isfull() const
{
    return top == MAX;
}

bool Stack::pop(Item &it)
{
    if (top > 0)
    {
        it = item[--top];
        total += it.payment;
        cout << "An order has been processed, current total revenue : " << total << endl;
        return true;
    }
    else
    {
        return false;
    }
}

bool Stack::push(const Item &it)
{
    if (top < MAX)
    {
        item[top++] = it;
        return true;
    }
    else
    {
        return false;
    }
}

main.cpp :

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

using namespace std;

int main()
{
    Stack stack;
    customer cu;
    char ch;
    cout << "Press a to add a customer, P to process an order, and Q to exit." << endl;
    while (cin >> ch && toupper(ch) != 'Q')
    {
        while (cin.get() != '\n')
        {
            continue;
        }
        if (!isalpha(ch))
        {
            cout << '\a';
            continue;
        }
        switch (ch)
        {
        case 'a':
        case 'A':
            if (stack.isfull())
            {
                cout << "The order of 10 customers has been filled. Please process the existing order first !" << endl;
            }
            else
            {
                cout << "Add customer name : ";
                cin.getline(cu.fullname, 35);
                cout << "Add the customer's consumption amount : ";
                cin >> cu.payment;
                cout << "dsssd : " << stack.push(cu);
            }
            break;
        case 'p':
        case 'P':
            if (stack.isempty())
            {
                cout << " There are currently no unprocessed orders." << endl;
            }
            else
            {
                stack.pop(cu);
            }
            break;
        default:
            cout << " Input error!!!" << endl;
            break;
        }
        cout << "Press a to add a customer, P to process an order, and Q to exit." << endl;
    }
    return 0;
}

6.下面是一个类声明:

class Move
{
private:
    double x;
    double y;

public:
    Move(double a = 0, double b = 0); //sets x, y to a, b
    showmove() const;                 // shows current x, y values
    Move add(const Move &m) const;
    // this function adds x of m to x of invoking object to get new x,
    // adds y of m to y of invoking object to get new y, creates a new
    // move object initialized to new x, y values and returns it
    reset(double a = 0, double b = 0); // resets x,y to a, b
}

请提供成员函数的定义和测试这个类的程序。

move.h :

#ifndef MOVE_H
#define MOVE_H

class Move
{
private:
    double x;
    double y;

public:
    Move(double a = 0, double b = 0); //sets x, y to a, b
    void showmove() const;            // shows current x, y values
    Move add(const Move &m) const;
    // this function adds x of m to x of invoking object to get new x,
    // adds y of m to y of invoking object to get new y, creates a new
    // move object initialized to new x, y values and returns it
    void reset(double a = 0, double b = 0); // resets x,y to a, b
};

#endif

move.cpp :

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

Move::Move(double a, double b)
{
    x = a;
    y = b;
}

Move Move::add(const Move &m) const
{
    return Move(x + m.x, y + m.y);
}

void Move::showmove() const
{
    std::cout << "x is :" << x << std::endl;
    std::cout << "y is :" << y << std::endl;
}
void Move::reset(double a, double b)
{
    x = a;
    y = b;
}

main.cpp :

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

int main()
{
    Move m1(1, 2), m2(3, 4);
    m1.showmove();
    m2.showmove();
    m1.add(m2).showmove();
    m1.reset(5, 6);
    m1.showmove();
    return 0;
}

7.Betelgeusean plorg有这些特征.

数据:

  • plorg的名称不超过19个字符;

  • plorg有满意指数(CI),这是一个整数。

操作:

  • 新的plorg将有名称,其CI值为50;

  • plorg的CI可以修改;

  • plorg可以报告其名称和CI;

  • plorg的默认名称为“Plorga”。

请编写一个Plorg类声明(包括数据成员和成员函数原型)来表示plorg,并编写成员函数的函数定义。然后编写一个小程序,以演示Plorg类的所有特性。

plorg.h :

#ifndef PLORG_H
#define PLORG_H

class Plorg
{
private:
    char name[19];
    int CI;

public:
    Plorg();
    Plorg( const char *n, int ci);
    void show();
    void setCI(int ci);
};

#endif

plorg.cpp :

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

Plorg::Plorg()
{
    strcpy(name, "Plorg");
    CI = 0;
}
Plorg::Plorg(const char *n, int ci)
{
    strcpy(name, n);
    CI = ci;
}

void Plorg::setCI(int ci)
{
    CI = ci;
}

void Plorg::show()
{
    std::cout << "name : " << name << ", CI: " << CI << std::endl;
}

main.cpp :

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

int main()
{
    Plorg p1, p2("plorg2", 50);
    p1.show();
    p2.show();
    p1.setCI(30);
    p1.show();
}

8.可以将简单列表描述成下面这样:

  • 可存储0或多个类型的列表;

  • 可创建空列表

  • 可在列表中添加数据项;

  • 可确定列表是否为空;

  • 可确定列表是否已满;

  • 可访问列表中每一个数据项,并对它执行某种操作。

可以看到,这个列表确实很简单,例如它不允许插入或删除数据项。

请设计一个List类来表示这中数据类型。您应提供头文件list.h和实现文件list.cpp.前者包含定义,后者包含实现这个类的方法。您还应创建一个简短的程序来实现这个类。

该表的规范很简单,这主要旨在简化这个编程练习,可以选择使用数组或链表来实现这个列表,但公有结构不应依赖与说做的选择。也就是说,公有接口不应有数组索引,节点指针等。应使用通用概念来表达创建列表、在列表中添加数据项等操作。对于访问数据项以及执行操作,通常应使用将函数指针做为参数的函数来处理:

void visit(void (*pf) (Item&));

其中,pf指向一个将Item引用作为参数的函数(不是成员函数),Item是列表中数据项的类型,visit()函数将该函数用于列表中的每个数据项。

list.h :

#ifndef LIST_H
#define LIST_H

typedef int Item;
const int MAX = 10;
class List
{
private:
    Item ITEM[MAX];
    int COUNT;

public:
    List();
    bool isfull();
    bool isempty();
    bool addItem(Item it);
    Item *item();
    int count();
    void visit(void (*pf)(Item &));
};

#endif

list.cpp :

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

List::List()
{
    COUNT = 0;
}

bool List::isfull()
{
    return COUNT == MAX;
}

bool List::isempty()
{
    return COUNT == 0;
}
bool List::addItem(Item it)
{
    if (this->isfull())
    {
        std::cout << "full already, add fail. " << std::endl;
        return false;
    }
    else
    {
        ITEM[COUNT++] = it;
        return true;
    }
}

Item *List::item()
{
    return ITEM;
}

int List::count()
{
    return COUNT;
}

void List::visit(void (*pf)(Item &))
{
    for (int i = 0; i < COUNT; i++)
    {
        (*pf)(ITEM[i]);
    }
}

main.cpp :

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

void intadd2(int &n);

int main()
{
    List l;
    l.addItem(1);
    l.addItem(2);
    l.addItem(3);
    for (int i = 0; i < 3; i++)
    {
        std::cout << l.item()[i] << std::endl;
    }
    l.visit(intadd2);
    for (int i = 0; i < 3; i++)
    {
        std::cout << l.item()[i] << std::endl;
    }
    return 0;
}

void intadd2(int &n)
{
    n += 2;
}

 第十一章课后习题答案

复习题

1.使用成员函数Stonewt类重载乘法运算符,该运算符将数据成员与double类型的值相乘。注意使用英石和磅表示时,需要进位。也就是说,将10英石8磅乘以2等于21英石2磅(1 英石=14 磅)。

Stonewt Stonewt::operator*(double a)
{
    this->stone=this->stone*a+this->pounds*a/14;
    this->pounds=(this->pounds*a)%14;
    return *this;
}

2.友元函数和成员函数之间的区别是什么?

成员函数是类定义的一部分,通过特定的对象来调用。成员函数可以隐式访问调用对象的成员,而无需使用成员运算符。友元函数不是类的组成部分,因此被称为直接函数调用。友元函数不能隐式访问类成员,而需要将成员运算符用作参数传递的对象。

3.非成员函数必须是友元才能访问类成员吗?

要访问私有成员,它必须是友元,但要访问共有成员,可以不是友元。

4.使用友元函数为Stonewt类重载乘法运算符,该运算符将double值与Stone值相乘。

friend Stonewt Stonewt::operator*(double a, Stonewt &s);


Stonewt operator*(double a, Stonewt &s)
{
    s.stone = s.stone * a + s.pounds * a / 14;
    s.pounds=( s.pounds * a ) % 14;
    return s;
}

5.那些运算符不能重载?

  • sizeof

  • .

  • .*

  • ::

  • ?:

6.在重载运算符=、( )、[ ]和->时,有什么限制?

这些运算符必须使用成员函数来定义。

7.为Vector类定义一个转换函数,将Vector类转换为一个double类型的值,后者表示矢量的长度。

operator double() {return mag}

编程练习

1.修改程序清单11.15,使之将一系列连续的随机漫步者位置写到文件中。对于每个位置,用步号进行标示。 另外,让该程序将初始条件(目标距离和步长)以结果小结写入到该文件中。该文件的内容与下面类似

Target Distance: 100, Step Size: 20
0: (x,y) = (0, 0)
1: (x,y) = (-11.4715, 16.383)
2: (x,y) = (-8.68807, -3.42232)
...
26: (x,y) = (42.2919, -78.2594)
27: (x,y) = (58.6749, -89.7309)
After 27 steps, the subject has the following location:
(x,y) = (58.6749, -89.7309)
or
(m,a) = (107.212, -56.8194)
Average outward distance per step = 3.97081

vect.h:

// vect.h -- Vector class with <<, mode state
#ifndef VECTOR_H_
#define VECTOR_H_
#include <iostream>
namespace VECTOR
{
    class Vector
    {
    public:
        enum Mode {RECT, POL};
    // RECT for rectangular, POL for Polar modes
    private:
        double x;          // horizontal value
        double y;          // vertical value
        double mag;        // length of vector
        double ang;        // direction of vector in degrees
        Mode mode;         // RECT or POL
    // private methods for setting values
        void set_mag();
        void set_ang();
        void set_x();
        void set_y();
    public:
       Vector();
        Vector(double n1, double n2, Mode form = RECT);
        void reset(double n1, double n2, Mode form = RECT);
        ~Vector();
        double xval() const {return x;}       // report x value
        double yval() const {return y;}       // report y value
        double magval() const {return mag;}   // report magnitude
        double angval() const {return ang;}   // report angle
        void polar_mode();                    // set mode to POL
        void rect_mode();                     // set mode to RECT
    // operator overloading
        Vector operator+(const Vector & b) const;
        Vector operator-(const Vector & b) const;
        Vector operator-() const;
        Vector operator*(double n) const;
    // friends
        friend Vector operator*(double n, const Vector & a);
        friend std::ostream & operator<<(std::ostream & os, const Vector & v);
    };

}   // end namespace VECTOR
#endif

vect.cpp:

// vect.cpp -- methods for the Vector class
#include <cmath>
#include "vect.h"   // includes <iostream>
using std::sqrt;
using std::sin;
using std::cos;
using std::atan;
using std::atan2;
using std::cout;

namespace VECTOR
{
    // compute degrees in one radian
    const double Rad_to_deg = 45.0 / atan(1.0);
    // should be about 57.2957795130823

    // private methods
    // calculates magnitude from x and y
    void Vector::set_mag()
    {
        mag = sqrt(x * x + y * y);
    }

    void Vector::set_ang()
    {
        if (x == 0.0 && y == 0.0)
            ang = 0.0;
        else
            ang = atan2(y, x);
    }

    // set x from polar coordinate
    void Vector::set_x()
    {
        x = mag * cos(ang);
    }

    // set y from polar coordinate
    void Vector::set_y()
    {
        y = mag * sin(ang);
    }

    // public methods
    Vector::Vector()             // default constructor
    {
        x = y = mag = ang = 0.0;
        mode = RECT;
    }

    // construct vector from rectangular coordinates if form is r
    // (the default) or else from polar coordinates if form is p
    Vector::Vector(double n1, double n2, Mode form)
    {
        mode = form;
        if (form == RECT)
         {
             x = n1;
             y = n2;
             set_mag();
             set_ang();
        }
        else if (form == POL)
        {
             mag = n1;
             ang = n2 / Rad_to_deg;
             set_x();
             set_y();
        }
        else
        {
             cout << "Incorrect 3rd argument to Vector() -- ";
             cout << "vector set to 0\n";
             x = y = mag = ang = 0.0;
             mode = RECT;
        }
    }

    // reset vector from rectangular coordinates if form is
    // RECT (the default) or else from polar coordinates if
    // form is POL
    void Vector:: reset(double n1, double n2, Mode form)
    {
        mode = form;
        if (form == RECT)
         {
             x = n1;
             y = n2;
             set_mag();
             set_ang();
        }
        else if (form == POL)
        {
             mag = n1;
             ang = n2 / Rad_to_deg;
             set_x();
             set_y();
        }
        else
        {
             cout << "Incorrect 3rd argument to Vector() -- ";
             cout << "vector set to 0\n";
             x = y = mag = ang = 0.0;
             mode = RECT;
        }
    }

    Vector::~Vector()    // destructor
    {
    }

    void Vector::polar_mode()    // set to polar mode
    {
        mode = POL;
    }

    void Vector::rect_mode()     // set to rectangular mode
    {
        mode = RECT;
    }

    // operator overloading
    // add two Vectors
    Vector Vector::operator+(const Vector & b) const
    {
        return Vector(x + b.x, y + b.y);
    }

    // subtract Vector b from a
    Vector Vector::operator-(const Vector & b) const
    {
        return Vector(x - b.x, y - b.y);
    }

    // reverse sign of Vector
    Vector Vector::operator-() const
    {
        return Vector(-x, -y);
    }

    // multiply vector by n
    Vector Vector::operator*(double n) const
    {
        return Vector(n * x, n * y);
    }

    // friend methods
    // multiply n by Vector a
    Vector operator*(double n, const Vector & a)
    {
        return a * n;
    }

    // display rectangular coordinates if mode is RECT,
    // else display polar coordinates if mode is POL
    std::ostream & operator<<(std::ostream & os, const Vector & v)
    {
        if (v.mode == Vector::RECT)
             os << "(x,y) = (" << v.x << ", " << v.y << ")";
        else if (v.mode == Vector::POL)
        {
             os << "(m,a) = (" << v.mag << ", "
                 << v.ang * Rad_to_deg << ")";
        }
        else
             os << "Vector object mode is invalid";
        return os;
    }

}  // end namespace VECTOR

randwalk.cpp:

// randwalk.cpp -- using the Vector class
// compile with the vect.cpp file
#include <iostream>
#include <cstdlib>      // rand(), srand() prototypes
#include <ctime>        // time() prototype
#include "vect.h"
#include <fstream>
int main()
{
    using namespace std;
    using VECTOR::Vector;
    srand(time(0));     // seed random-number generator
    double direction;
    Vector step;
    Vector result(0.0, 0.0);
    unsigned long steps = 0;
    double target;
    double dstep;

    //for write
    ofstream fout;
    fout.open("walkinfo.txt");

    cout << "Enter target distance (q to quit): ";
    while (cin >> target)
    {
        cout << "Enter step length: ";
        if (!(cin >> dstep))
            break;

        //write to file
        fout << "Target Destance: " << target << ", ";
        fout << "Step Size: " << dstep << endl;
        while (result.magval() < target)
        {
            direction = rand() % 360;
            step.reset(dstep, direction, Vector::POL);
            result = result + step;
            fout << steps << ": " << result << endl;
            steps++;
        }
        cout << "After " << steps << " steps, the subject "
            "has the following location:\n";
        cout << result << endl;
        result.polar_mode();
        cout << " or\n" << result << endl;
        cout << "Average outward distance per step = "
            << result.magval()/steps << endl;

        fout << "After " << steps << " steps, the subject "
            "has the following location:\n";
        fout << result << endl;
        result.polar_mode();
        fout << " or\n" << result << endl;
        fout << "Average outward distance per step = "
            << result.magval()/steps << endl;
        steps = 0;
        result.reset(0.0, 0.0);
        cout << "Enter target distance (q to quit): ";
    }
    cout << "Bye!\n";
/* keep window open
    cin.clear();
    while (cin.get() != '\n')
        continue;
    cin.get();
*/
    fout.close();
    return 0;
}

2.对vector类的头文件(程序清单11.13)和实现文件(程序清单11.14)进行修改,使其不再存储矢量的长度和角度,而是在magval()和angval()被调用时计算他们。应保留公有接口不变(公有方法及其参数不变),但对私有部分(包括一些私有方法)和方法实现进行修改。然后,使用程序清单11.15对修改后的版本进行测试,结果应该与以前相同,因为vector类的公有接口与原来相同。

vect.h:

// vect.h -- Vector class with <<, mode state
#ifndef VECTOR_H_
#define VECTOR_H_
#include <iostream>
namespace VECTOR
{
    class Vector
    {
    public:
        enum Mode {RECT, POL};
    // RECT for rectangular, POL for Polar modes
    private:
        double x;          // horizontal value
        double y;          // vertical value
        Mode mode;         // RECT or POL
    // private methods for setting values
        double get_mag() const;
        double get_ang() const;
        double get_x();
        double get_y();
    public:
       Vector();
        Vector(double n1, double n2, Mode form = RECT);
        void reset(double n1, double n2, Mode form = RECT);
        ~Vector();
        double xval() const {return x;}       // report x value
        double yval() const {return y;}       // report y value
        double magval() const {return get_mag();}   // report magnitude
        double angval() const {return get_ang();}   // report angle
        void polar_mode();                    // set mode to POL
        void rect_mode();                     // set mode to RECT
    // operator overloading
        Vector operator+(const Vector & b) const;
        Vector operator-(const Vector & b) const;
        Vector operator-() const;
        Vector operator*(double n) const;
    // friends
        friend Vector operator*(double n, const Vector & a);
        friend std::ostream & operator<<(std::ostream & os, const Vector & v);
    };

}   // end namespace VECTOR
#endif

vect.cpp:

// vect.cpp -- methods for the Vector class
#include <cmath>
#include "vect.h"   // includes <iostream>
using std::sqrt;
using std::sin;
using std::cos;
using std::atan;
using std::atan2;
using std::cout;

namespace VECTOR
{
    // compute degrees in one radian
    const double Rad_to_deg = 45.0 / atan(1.0);
    // should be about 57.2957795130823

    // private methods
    // calculates magnitude from x and y
    double Vector::get_mag() const
    {
        return sqrt(x * x + y * y);
    }

    double Vector::get_ang() const
    {
        if (x == 0.0 && y == 0.0)
            return 0.0;
        else
            return atan2(y, x);
    }

    // set x from polar coordinate
    double Vector::get_x()
    {
        return get_mag() * cos(get_ang());
    }

    // set y from polar coordinate
    double Vector::get_y()
    {
        return get_mag() * sin(get_ang());
    }

    // public methods
    Vector::Vector()             // default constructor
    {
        x = y  = 0.0;
        mode = RECT;
    }

    // construct vector from rectangular coordinates if form is r
    // (the default) or else from polar coordinates if form is p
    Vector::Vector(double n1, double n2, Mode form)
    {
        mode = form;
        if (form == RECT)
         {
             x = n1;
             y = n2;
        }
        else if (form == POL)
        {
             x =n1 * cos(n2);
             y =n1 * sin(n2);
        }
        else
        {
             cout << "Incorrect 3rd argument to Vector() -- ";
             cout << "vector set to 0\n";
             x = y  = 0.0;
             mode = RECT;
        }
    }

    // reset vector from rectangular coordinates if form is
    // RECT (the default) or else from polar coordinates if
    // form is POL
    void Vector:: reset(double n1, double n2, Mode form)
    {
        mode = form;
        if (form == RECT)
         {
             x = n1;
             y = n2;
        }
        else if (form == POL)
        {
            x =n1 * cos(n2);
            y =n1 * sin(n2);
        }
        else
        {
             cout << "Incorrect 3rd argument to Vector() -- ";
             cout << "vector set to 0\n";
             x = y = 0.0;
             mode = RECT;
        }
    }

    Vector::~Vector()    // destructor
    {
    }

    void Vector::polar_mode()    // set to polar mode
    {
        mode = POL;
    }

    void Vector::rect_mode()     // set to rectangular mode
    {
        mode = RECT;
    }

    // operator overloading
    // add two Vectors
    Vector Vector::operator+(const Vector & b) const
    {
        return Vector(x + b.x, y + b.y);
    }

    // subtract Vector b from a
    Vector Vector::operator-(const Vector & b) const
    {
        return Vector(x - b.x, y - b.y);
    }

    // reverse sign of Vector
    Vector Vector::operator-() const
    {
        return Vector(-x, -y);
    }

    // multiply vector by n
    Vector Vector::operator*(double n) const
    {
        return Vector(n * x, n * y);
    }

    // friend methods
    // multiply n by Vector a
    Vector operator*(double n, const Vector & a)
    {
        return a * n;
    }

    // display rectangular coordinates if mode is RECT,
    // else display polar coordinates if mode is POL
    std::ostream & operator<<(std::ostream & os, const Vector & v)
    {
        if (v.mode == Vector::RECT)
             os << "(x,y) = (" << v.x << ", " << v.y << ")";
        else if (v.mode == Vector::POL)
        {
             os << "(m,a) = (" << v.magval() << ", "
                 << v.angval() * Rad_to_deg << ")";
        }
        else
             os << "Vector object mode is invalid";
        return os;
    }

}  // end namespace VECTOR

randwalk.cpp:

// randwalk.cpp -- using the Vector class
// compile with the vect.cpp file
#include <iostream>
#include <cstdlib>      // rand(), srand() prototypes
#include <ctime>        // time() prototype
#include "vect.h"
int main()
{
    using namespace std;
    using VECTOR::Vector;
    srand(time(0));     // seed random-number generator
    double direction;
    Vector step;
    Vector result(0.0, 0.0);
    unsigned long steps = 0;
    double target;
    double dstep;
    cout << "Enter target distance (q to quit): ";
    while (cin >> target)
    {
        cout << "Enter step length: ";
        if (!(cin >> dstep))
            break;

        while (result.magval() < target)
        {
            direction = rand() % 360;
            step.reset(dstep, direction, Vector::POL);
            result = result + step;
            steps++;
        }
        cout << "After " << steps << " steps, the subject "
            "has the following location:\n";
        cout << result << endl;
        result.polar_mode();
        cout << " or\n" << result << endl;
        cout << "Average outward distance per step = "
            << result.magval()/steps << endl;
        steps = 0;
        result.reset(0.0, 0.0);
        cout << "Enter target distance (q to quit): ";
    }
    cout << "Bye!\n";
/* keep window open
    cin.clear();
    while (cin.get() != '\n')
        continue;
    cin.get();
*/
    return 0;
}

3.修改程序清单11.15,使之报告N次测试中的提高、最低和平均步数(其中N是用户输入的整数),而不是报告每次测试的结果。

vect.h:

// vect.h -- Vector class with <<, mode state
#ifndef VECTOR_H_
#define VECTOR_H_
#include <iostream>
namespace VECTOR
{
    class Vector
    {
    public:
        enum Mode {RECT, POL};
    // RECT for rectangular, POL for Polar modes
    private:
        double x;          // horizontal value
        double y;          // vertical value
        double mag;        // length of vector
        double ang;        // direction of vector in degrees
        Mode mode;         // RECT or POL
    // private methods for setting values
        void set_mag();
        void set_ang();
        void set_x();
        void set_y();
    public:
       Vector();
        Vector(double n1, double n2, Mode form = RECT);
        void reset(double n1, double n2, Mode form = RECT);
        ~Vector();
        double xval() const {return x;}       // report x value
        double yval() const {return y;}       // report y value
        double magval() const {return mag;}   // report magnitude
        double angval() const {return ang;}   // report angle
        void polar_mode();                    // set mode to POL
        void rect_mode();                     // set mode to RECT
    // operator overloading
        Vector operator+(const Vector & b) const;
        Vector operator-(const Vector & b) const;
        Vector operator-() const;
        Vector operator*(double n) const;
    // friends
        friend Vector operator*(double n, const Vector & a);
        friend std::ostream & operator<<(std::ostream & os, const Vector & v);
    };

}   // end namespace VECTOR
#endif

vect.cpp:

// vect.cpp -- methods for the Vector class
#include <cmath>
#include "vect.h"   // includes <iostream>
using std::sqrt;
using std::sin;
using std::cos;
using std::atan;
using std::atan2;
using std::cout;

namespace VECTOR
{
    // compute degrees in one radian
    const double Rad_to_deg = 45.0 / atan(1.0);
    // should be about 57.2957795130823

    // private methods
    // calculates magnitude from x and y
    void Vector::set_mag()
    {
        mag = sqrt(x * x + y * y);
    }

    void Vector::set_ang()
    {
        if (x == 0.0 && y == 0.0)
            ang = 0.0;
        else
            ang = atan2(y, x);
    }

    // set x from polar coordinate
    void Vector::set_x()
    {
        x = mag * cos(ang);
    }

    // set y from polar coordinate
    void Vector::set_y()
    {
        y = mag * sin(ang);
    }

    // public methods
    Vector::Vector()             // default constructor
    {
        x = y = mag = ang = 0.0;
        mode = RECT;
    }

    // construct vector from rectangular coordinates if form is r
    // (the default) or else from polar coordinates if form is p
    Vector::Vector(double n1, double n2, Mode form)
    {
        mode = form;
        if (form == RECT)
         {
             x = n1;
             y = n2;
             set_mag();
             set_ang();
        }
        else if (form == POL)
        {
             mag = n1;
             ang = n2 / Rad_to_deg;
             set_x();
             set_y();
        }
        else
        {
             cout << "Incorrect 3rd argument to Vector() -- ";
             cout << "vector set to 0\n";
             x = y = mag = ang = 0.0;
             mode = RECT;
        }
    }

    // reset vector from rectangular coordinates if form is
    // RECT (the default) or else from polar coordinates if
    // form is POL
    void Vector:: reset(double n1, double n2, Mode form)
    {
        mode = form;
        if (form == RECT)
         {
             x = n1;
             y = n2;
             set_mag();
             set_ang();
        }
        else if (form == POL)
        {
             mag = n1;
             ang = n2 / Rad_to_deg;
             set_x();
             set_y();
        }
        else
        {
             cout << "Incorrect 3rd argument to Vector() -- ";
             cout << "vector set to 0\n";
             x = y = mag = ang = 0.0;
             mode = RECT;
        }
    }

    Vector::~Vector()    // destructor
    {
    }

    void Vector::polar_mode()    // set to polar mode
    {
        mode = POL;
    }

    void Vector::rect_mode()     // set to rectangular mode
    {
        mode = RECT;
    }

    // operator overloading
    // add two Vectors
    Vector Vector::operator+(const Vector & b) const
    {
        return Vector(x + b.x, y + b.y);
    }

    // subtract Vector b from a
    Vector Vector::operator-(const Vector & b) const
    {
        return Vector(x - b.x, y - b.y);
    }

    // reverse sign of Vector
    Vector Vector::operator-() const
    {
        return Vector(-x, -y);
    }

    // multiply vector by n
    Vector Vector::operator*(double n) const
    {
        return Vector(n * x, n * y);
    }

    // friend methods
    // multiply n by Vector a
    Vector operator*(double n, const Vector & a)
    {
        return a * n;
    }

    // display rectangular coordinates if mode is RECT,
    // else display polar coordinates if mode is POL
    std::ostream & operator<<(std::ostream & os, const Vector & v)
    {
        if (v.mode == Vector::RECT)
             os << "(x,y) = (" << v.x << ", " << v.y << ")";
        else if (v.mode == Vector::POL)
        {
             os << "(m,a) = (" << v.mag << ", "
                 << v.ang * Rad_to_deg << ")";
        }
        else
             os << "Vector object mode is invalid";
        return os;
    }

}  // end namespace VECTOR

randwalk.cpp:

// randwalk.cpp -- using the Vector class
// compile with the vect.cpp file
#include <iostream>
#include <cstdlib>      // rand(), srand() prototypes
#include <ctime>        // time() prototype
#include "vect.h"
int main()
{
    using namespace std;
    using VECTOR::Vector;
    srand(time(0));     // seed random-number generator
    double direction;
    Vector step;
    Vector result(0.0, 0.0);
    unsigned long steps = 0;
    double target;
    double dstep;
    int times;
    unsigned long max, min;
    max = min = 0;

    cout << "Enter Times:";
    if(!(cin >> times))
    {
        cout << "Input error !, program ended." << endl;
        return 0;
    }
    cout << "Enter target distance (q to quit): ";
    for(int i = 0; i < times; ++i)
    {
       cin >> target;
       cout << "Enter step length: ";
       if(!(cin >> dstep))
       {
           break;
       }

       while(result.magval() < target)
       {
           direction = rand() % 360;
           step.reset(dstep, direction, Vector::POL);
           result = result + step;
           steps++;
       }
       if(min == 0)
       {
           min = steps;
       }

       if(steps > max)
       {
          max = steps;
       }
       else if(steps < min)
       {
           min = steps;
       }

       result.reset(0.0, 0.0);
       if(i < times - 1)
       {
           cout << "Enter target distance (q to quit): ";
       }
    }
    cout << "Max: " << max << endl;
    cout << "Min: " << min << endl;
    cout << "Bye!\n";
/* keep window open
    cin.clear();
    while (cin.get() != '\n')
        continue;
    cin.get();
*/
    return 0;
}

4.重新编写最后的Time类示例(程序清单11.10、程序清单11.11和程序清单11.12),使用友元函数来实现所有的重载运算符。

mytime3.h:

// mytime3.h -- Time class with friends
#ifndef MYTIME3_H_
#define MYTIME3_H_
#include <iostream>

class Time
{
private:
    int hours;
    int minutes;
public:
    Time();
    Time(int h, int m = 0);
    void AddMin(int m);
    void AddHr(int h);
    void Reset(int h = 0, int m = 0);
    friend Time operator+(const Time & t1, const Time & t2);
    friend Time operator-(const Time & t1, const Time & t2);
    friend Time operator*(const Time & t, double m);
    friend Time operator*(double m, const Time & t)
        { return t * m; }   // inline definition
    friend std::ostream & operator<<(std::ostream & os, const Time & t);

};
#endif

mytime3.cpp:

// mytime3.cpp  -- implementing Time methods
#include "mytime3.h"

Time::Time()
{
    hours = minutes = 0;
}

Time::Time(int h, int m )
{
    hours = h;
    minutes = m;
}

void Time::AddMin(int m)
{
    minutes += m;
    hours += minutes / 60;
    minutes %= 60;
}

void Time::AddHr(int h)
{
    hours += h;
}

void Time::Reset(int h, int m)
{
    hours = h;
    minutes = m;
}

Time operator+(const Time & t1, const Time & t2)
{
    Time sum;
    sum.minutes = t1.minutes + t2.minutes;
    sum.hours = t1.hours + t2.hours + sum.minutes / 60;
    sum.minutes %= 60;
    return sum;
}

Time operator-(const Time & t1, const Time & t2)
{
    Time diff;
    int tot1, tot2;
    tot1 = t1.minutes + 60 * t1.hours;
    tot2 = t2.minutes + 60 * t2.hours;
    diff.minutes = (tot2 - tot1) % 60;
    diff.hours = (tot2 - tot1) / 60;
    return diff;
}

Time operator*(const Time & t, double m)
{
    Time result;
    long totalminutes = t.hours * m * 60 + t.minutes * m;
    result.hours = totalminutes / 60;
    result.minutes = totalminutes % 60;
    return result;
}

std::ostream &
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值