转载公众号: 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 &