《C++primerplus》第11章练习题
阅读原文时间:2023年07月09日阅读:4

1.修改程序清单11.5(随机漫步),使之以特定的格式将结果写入文件中。

//vector.h -- Vector Class
#ifndef _VECTOR_H_
#define _VECTOR_H_
#include
#include
namespace VECTOR
{
class Vector
{
public:
enum Mode{RECT,POL};

private:  
    double x;  
    double y;  
    double mag;  
    double ang;  
    Mode mode;  
//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; }  
    double yval() const { return y; }  
    double magval() const { return mag; }  
    double angval() const { return ang; }  
    void polar\_mode();  
    void rect\_mode();  
//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, Vector & a);  
    friend std::ostream & operator<<(std::ostream & os, const Vector & v);  
    friend std::ofstream & operator<<(std::ofstream & ofs, const Vector & v);  
};  

} //end namespace VECTOR

#endif // VECTOR_H_INCLUDED

//vector.cpp -- Methods for Vector class
#include
#include "vector.h"

using std::sqrt;
using std::sin;
using std::cos;
using std::atan;
using std::atan2;
using std::cout;

namespace VECTOR
{
const double Rad_to_deg = 45.0 / atan(1.0);

//private methods  
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);  
    }  
}

void Vector::set\_x()  
{  
    x = mag \* cos(ang);  
}

void Vector::set\_y()  
{  
    y = mag \* sin(ang);  
}

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

//construct vector from rectangular or polar coordinate  
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;  
        mode = RECT;  
    }  
}

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;  
        mode = RECT;  
    }  
}

Vector::~Vector()  
{  
}

void Vector::rect\_mode()  
{  
    mode = RECT;  
}

void Vector::polar\_mode()  
{  
    mode = POL;  
}

Vector Vector::operator + (const Vector & b)const  
{  
    return Vector(x + b.x,y + b.y);  
}

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

Vector Vector::operator - ()const  
{  
    return Vector(-x,-y);  
}

Vector Vector::operator \* (double n)const  
{  
    return Vector(n\*x,n\*y);  
}

Vector operator \* (double n,const Vector & a)  
{  
    return a \* n;  
}

//display coordinates  
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<<")";  
    }  
    else  
        os<<"Vector object is invalid";  
    return os;  
}

//再为文件对象重载一个输出函数  
std::ofstream & operator<<(std::ofstream & ofs, const Vector & v)  
{  
    if(v.mode == Vector::RECT)  
        ofs<<"(x,y) = ("<<v.x<<","<<v.y<<")";  
    else if(v.mode == Vector::POL)  
    {  
        ofs<<"(m,a) = ("<<v.mag<<","<<v.ang<<")";  
    }  
    else  
        ofs<<"Vector object is invalid";  
    return ofs;  
}  

} //end namespace VECTOR

//randwalk.cpp -- using Vector Class
#include
#include
#include
#include "vector.h"

int main()
{
using namespace std;
using VECTOR::Vector;
srand(time(0)); //生成随机时间种子
double direction;

Vector step;    //表示移动的矢量  
Vector result(0.0,0.0);    //表示最终结果的矢量  
unsigned long steps = 0;  
double target;    //移动距离范围  
double dstep;    //每次移动的步长

ofstream outfile;    //文件对象  
outfile.open("record.txt");    //打开文件  
cout<<"Enter target distance (q to quit): ";  
while(cin>>target)  
{  
    cout<<"Enter step length: ";  
    if(!(cin>>dstep))    //获取步长  
        break;

    outfile<<"Target Distance: "<<target<<", Step Size: "<<dstep<<endl;  
    while(result.magval() < target)  
    {  
        direction = rand()%360;    //随机生成一个方向(角度)  
        step.reset(dstep,direction,Vector::POL);    //利用步长和方向设置移动的矢量  
        result = result + step;    //(重载+)结果矢量更新  
        outfile<<steps<<": (x,y) = "<<"("<<result.xval()<<","<<result.yval()<<")"<<endl;  
        steps++;  
    }

    outfile<<"After "<<steps<<" steps, the subject has the following location:\\n";  
    outfile<<result<<endl;  
    result.polar\_mode();  
    outfile<<" or\\n"<<result<<endl;  
    outfile<<"Average outward distance per step = "<<result.magval()/steps<<endl;  
    steps = 0;  
    result.reset(0.0,0.0);  
    cout<<"Enter target distance (q to quit): ";  
}  
outfile.close();    //关闭文件  
cout<<"Bye!\\n";  
cin.clear();  
while(cin.get() != '\\n')  
    continue;

return 0;  

}

2.保留类的公有接口不变,修改私有部分,使得其不再存储长度mag和角度ang的值,而是在调用magval()和angval()时计算它们。重新测试,结果应与原来相同。

主函数没动。类的声明和实现如下:

//vector.h -- Vector Class
#ifndef _VECTOR_H_
#define _VECTOR_H_
#include
#include
namespace VECTOR
{
class Vector
{
public:
enum Mode{RECT,POL};

private:  
    double x;  
    double y;  
    Mode mode;  
//private methods for setting values  
    void set\_x(double m,double a);    //使用长度和方向换算x和y  
    void set\_y(double m,double a);

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; }  
    double yval() const { return y; }  
    double magval() const;    //调用时通过x和y计算长度和方向  
    double angval() const;  
    void polar\_mode();  
    void rect\_mode();  
//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, Vector & a);  
    friend std::ostream & operator<<(std::ostream & os, const Vector & v);  
    friend std::ofstream & operator<<(std::ofstream & ofs, const Vector & v);  
};  

} //end namespace VECTOR

#endif // VECTOR_H_INCLUDED

//vector.cpp -- Methods for Vector class
#include
#include "vector.h"

using std::sqrt;
using std::sin;
using std::cos;
using std::atan;
using std::atan2;
using std::cout;

namespace VECTOR
{
const double Rad_to_deg = 45.0 / atan(1.0);

//private methods  
void Vector::set\_x(double m,double a )  
{  
    x = m \* cos(a/Rad\_to\_deg);  
}

void Vector::set\_y(double m,double a )  
{  
    y = m \* sin(a/Rad\_to\_deg);  
}

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

double Vector::magval() const  
{  
    return sqrt(x\*x +y\*y);  
}

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

//construct vector from rectangular or polar coordinate  
Vector::Vector(double n1, double n2, Mode form)  
{  
    mode = form;  
    if (form == RECT)  
    {  
        x = n1;  
        y = n2;  
    }  
    else if (form == POL)  
    {  
        set\_x(n1,n2);  
        set\_y(n1,n2);  
    }  
    else  
    {  
        cout << "Incorrect 3rd argument to Vector() -- ";  
        cout << "Vector set to 0\\n";  
        x = y = 0;  
        mode = RECT;  
    }  
}

void Vector::reset(double n1, double n2, Mode form)  
{  
    mode = form;  
    if (form == RECT)  
    {  
        x = n1;  
        y = n2;  
    }  
    else if (form == POL)  
    {  
        set\_x(n1,n2);  
        set\_y(n1,n2);  
    }  
    else  
    {  
        cout << "Incorrect 3rd argument to Vector() -- ";  
        cout << "Vector set to 0\\n";  
        x = y = 0;  
        mode = RECT;  
    }  
}

Vector::~Vector()  
{  
}

void Vector::rect\_mode()  
{  
    mode = RECT;  
}

void Vector::polar\_mode()  
{  
    mode = POL;  
}

Vector Vector::operator + (const Vector & b)const  
{  
    return Vector(x + b.x,y + b.y);  
}

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

Vector Vector::operator - ()const  
{  
    return Vector(-x,-y);  
}

Vector Vector::operator \* (double n)const  
{  
    return Vector(n\*x,n\*y);  
}

Vector operator \* (double n,const Vector & a)  
{  
    return a \* n;  
}

//display coordinates  
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()<<")";  
    }  
    else  
        os<<"Vector object is invalid";  
    return os;  
}

//再为文件对象重载一个输出函数  
std::ofstream & operator<<(std::ofstream & ofs, const Vector & v)  
{  
    if(v.mode == Vector::RECT)  
        ofs<<"(x,y) = ("<<v.x<<","<<v.y<<")";  
    else if(v.mode == Vector::POL)  
    {  
        ofs<<"(m,a) = ("<<v.magval()<<","<<v.angval()<<")";  
    }  
    else  
        ofs<<"Vector object is invalid";  
    return ofs;  
}  

} //end namespace VECTOR

3.继续修改上面的程序,不再写入每次测试的具体结果,而是由用户指定特定的测试次数N,写入N次测试的最大步数和最小步数。

//randwalk.cpp -- using Vector Class
#include
#include
#include
#include "vector.h"

int main()
{
using namespace std;
using VECTOR::Vector;
srand(time(0)); //生成随机时间种子
double direction;

Vector step;    //表示移动的矢量  
Vector result(0.0,0.0);    //表示最终结果的矢量  
unsigned long steps = 0;  
unsigned long max\_steps;  
unsigned long min\_steps;  
double target = 0;    //移动距离范围  
double dstep = 0;    //每次移动的步长  
unsigned test\_times = 0;  
unsigned N;    //用户指定的测试次数

//测试准备  
ofstream outfile;    //文件对象  
outfile.open("record.txt");    //打开文件  
cout<<"Enter times you want to test: ";  
if(cin>>N)  
{  
        cout<<"Enter target distance: ";  
        cin>>target;  
        cout<<"Enter step length: ";  
        cin>>dstep;  
}  
else  
{  
    N = 1;  
}  
outfile<<"Target Distance: "<<target<<", Step Size: "<<dstep<<endl;  
unsigned long \* all\_steps = new unsigned long \[N\];    //分配用于存储所有测试步数的数组指针

//测试过程  
while(test\_times<N)  
{  
    while(result.magval() < target)  
    {  
        direction = rand()%360;    //随机生成一个方向(角度)  
        step.reset(dstep,direction,Vector::POL);    //利用步长和方向设置移动的矢量  
        result = result + step;    //(重载+)结果矢量更新  
        steps++;  
    }  
    all\_steps\[test\_times\] = steps;    //存储此次测试的步数  
    outfile<<"Test "<<test\_times<<" used "<<steps<<" steps."<<endl;

    steps = 0;  
    result.reset(0.0,0.0);  
    test\_times++;  
}

//测试结果  
outfile<<"You have tested "<<N<<" times."<<endl;  
max\_steps = min\_steps = all\_steps\[0\];    //比较最大和最小步数  
for(unsigned i=0;i<N;i++)  
{  
    if(all\_steps\[i\]>max\_steps)  
        max\_steps = all\_steps\[i\];  
    else{};

    if(all\_steps\[i\]<min\_steps)  
        min\_steps = all\_steps\[i\];  
    else{};  
}  
outfile<<"Max steps: "<<max\_steps<<endl;  
outfile<<"Minimum steps: "<<min\_steps<<endl;

outfile.close();    //关闭文件  
cout<<"Bye!\\n";  
delete\[\]all\_steps;    //删除动态内存  
cin.clear();  
while(cin.get() != '\\n')  
    continue;

return 0;  

}

输出结果的形式:

7.实现一个复数类,使之能进行基本的加减乘运算,其中需要重载“<<”、“>>”、“~”、“+”、“-”、“*”等运算符,并定义友元函数。

//complex0.h -- Declaration of Complex Class
#ifndef _COMPLEX0_H_
#define _COMPLEX0_H_
#include
using namespace std;

class Ccomplex
{
private:
double m_real ;
double m_imag ;

public:
Ccomplex();
~Ccomplex();
void set_real(double i);
void set_imag(double r);
Ccomplex(double r ,double i );
Ccomplex operator +(const Ccomplex & c) const;
Ccomplex operator -(const Ccomplex & c) const;
Ccomplex operator *(const Ccomplex & c) const;
friend istream & operator >> (istream & is, Ccomplex & c);
friend ostream & operator << (ostream & os, const Ccomplex c);
friend Ccomplex operator ~(const Ccomplex c); //如果按引用传递上一句重载函数会不匹配,所以按值传递
friend Ccomplex operator *(const double n,const Ccomplex c);

};

#endif // _COMPLEX0_H_

//complex0.cpp -- Methods of Complex Class
#include"complex0.h"

Ccomplex::Ccomplex()
{
m_real = 0;
m_imag = 0;
}

Ccomplex::~Ccomplex()
{

}

Ccomplex::Ccomplex(double r = 0,double i = 0)
{
m_real = r;
m_imag = i;
}

void Ccomplex::set_imag(double i)
{
m_imag = i;
}

void Ccomplex::set_real(double r)
{
m_real = r;
}

Ccomplex operator ~(const Ccomplex c)
{
return Ccomplex(c.m_real,-c.m_imag);
}

Ccomplex Ccomplex::operator +(const Ccomplex & c) const
{
return Ccomplex(m_real + c.m_real,m_imag + c.m_imag);
}

Ccomplex Ccomplex::operator -(const Ccomplex & c) const
{
return Ccomplex(m_real - c.m_real,m_imag - c.m_imag);
}

Ccomplex Ccomplex::operator *(const Ccomplex & c) const
{
return Ccomplex(m_real*c.m_real - m_imag*c.m_imag , m_real*c.m_imag + m_imag*c.m_real);
}

Ccomplex operator *(const double n,const Ccomplex c)
{
return Ccomplex(n*c.m_real,n*c.m_imag);
}

istream & operator >> (istream & is, Ccomplex & c)
{
double tr,ti;
cout<<"real: "; is >> tr;
cout<<"imaginary: "; is >> ti;
c.set_real(tr);
c.set_imag(ti);
return is;
}

ostream & operator << (ostream & os, const Ccomplex c) { if(c.m_imag > 0)
{
os<<"("<<c.m_real<<"+"<<c.m_imag<<"i)";
}
else if(c.m_imag == 0)
{
os<<c.m_real<<endl;
}
else
{
os<<"("<<c.m_real<<c.m_imag<<"i)";
}
return os;
}

//main.cpp -- Using Complex Class
#include
#include"complex0.h"

int main()
{
Ccomplex a(3.0,4.0);
Ccomplex c;

cout<<"Enter a complex number (q to quit):\\n";  
while(cin>>c)  
{  
    cout<<"c is "<<c<<'\\n';  
    cout<<"complex conjugate is "<<~c<<'\\n';  
    cout<<"a is "<<a<<'\\n';  
    cout<<"a + c is "<<a + c<<'\\n';  
    cout<<"a - c is "<<a - c<<'\\n';  
    cout<<"a \* c is "<<a \* c<<'\\n';  
    cout<<"2 \* c is "<<2 \* c<<'\\n';  
    cout<<"Enter a complex number (q to quit):\\n";  
}  
cout<<"Done!\\n";

return 0;  

}

调试的过程中遇到了很多问题,总结一下:

1.友元函数和类本体有着同样的权力,能够访问私有成员

2.给出友元函数的定义时,不用加上类的“::”的解析符,和正常的函数定义一样

3.如果不是在类成员函数的实现里面的话,类本身是调不出它的私有成员的。比如在主函数里想通过 “.” 调出私有成员赋给另一个变量是不行的,除非通过公共接口。

4.分清楚重载运算符是想用于什么样形式的运算。如果想定义一种【该类——该运算符——其它类型】的运算,使用成员函数重载,“其它类型”以参数传递(如上面例程中的加减号重载);如果想定义一种【其它类型——该运算符——该类】的运算,使用友元函数重载(如上面例程中的>>,<<,~的重载)。