[C++ Primer Plus] Chapter 11 Using Classes

These skills may not be relevant to day-to-day work at all unless they are used frequently.

11.1 Operator overloading

  1. C++ decides which operation to use based on the number and types of operands.
  2. Applying the * operator to an address will result in the value stored at that address, but applying it to two numbers will result in their product.
  3. C++ allows operator overloading to be extended to user-defined types. For example, + is allowed to add two objects.
  4. To overload an operator, a special function form called an operator function is used.operatorop(argument-list)
  5. operator + ( ) overloads the + operator, and operator ( ) overloads the operator. [ ] is the array indexing operator.
district2 = sid + sara;
// 编译器发现,这三个操作数有一个是用户自定义的类型,
// 因此使用相应的运算符函数替换上述运算符:
district2 = sid.operator+(sara);
// 隐式地使用sid(因为它调用了方法)
// 显式地使用 sara对象(因为它被作为参数传递),来计算总和,并返回这个值。

11.2 Computing Time: An Example of Operator Overloading

  1. The purpose of declaring parameters as references is for efficiency. If you pass the Time object by value, the code will function the same, but by reference, it will be faster and use less memory.
  2. Using the return type Time means that the program will construct a copy of sum before deleting it, and the calling function will get that copy.
  3. Do not return references to local variables or temporary objects. After the function is executed, local variables and temporary objects will disappear, and references will point to non-existent data.

11.2.1 Restrictions on overloaded operators

  1. An overloaded operator must have at least one operand of a user-defined type, which prevents users from overloading operators for standard types.
  2. When using an operator, the original syntax rules of the operator cannot be violated. For example, the modulo operator (%) cannot be overloaded to take one operand.
  3. The precedence of operators cannot be modified.
  4. Cannot create new operator. For example, the operator **( ) function cannot be defined to express exponentiation.
  5. Some operators can only be overloaded via member functions. = assignment operator. ( ) function call operator. [ ] Subscript operator. -> operator for accessing class members through pointers.
  6. Some operators cannot be overloaded. sizeof operator. .Membership operator. . * Member pointer operator. :: scope resolution operator. ?: Conditional operator. typeid an RTTI operator. const_cast cast operator. dynamic_cast cast operator. reinterpret_cast cast operator. static_cast cast operator.

mytime0.h

#ifndef PRIMERPLUS_MYTIME0_H
#define PRIMERPLUS_MYTIME0_H
#include <iostream>
using namespace std;
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);
    Time Sum(const Time &t) const;

    Time operator+(const Time &t) const;    // 重载运算符+
    Time operator-(const Time &t) const;    // 重载运算符-
    Time operator*(double n) const;         // 重载运算符*,*左边操作数必须是类对象
    void show() const;
// 只有类声明可以决定哪一个函数是友元,以下是非成员友元函数
// friend Time operator*(double m, const Time & t);    // 重载运算符*,*左边操作数左侧是double值
    friend Time operator*(double m, const Time & t) {
    
     return t * m;} // 内联函数,其中使用成员函数重载运算符*
    friend ostream & operator<<(ostream & os, const Time & t);      // 重载运算符<<
};
#endif //PRIMERPLUS_MYTIME0_H

mytime0.cpp

#include "mytime0.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 Time::Sum(const Time &t) const
{
    
    
    Time sum;
    sum.minutes = minutes + t.minutes;
    sum.hours = hours + t.hours + sum.minutes / 60;
    sum.minutes %= 60;
    return sum;
}

// 运算符重载+
Time Time::operator+(const Time &t) const
{
    
    
    Time sum;
    sum.minutes = minutes + t.minutes;
    sum.hours = hours + t.hours + sum.minutes / 60;
    sum.minutes %= 60;
    return sum;
}

Time Time::operator-(const Time &t) const
{
    
    
    Time diff;
    int tot1, tot2;
    tot1 = t.minutes + 60 * t.hours;
    tot2 = minutes + 60 * hours;
    if (tot2 > tot1)
    {
    
    
        diff.minutes = (tot2 - tot1) % 60;
        diff.hours = (tot2 - tot1) / 60;
    }
    else
    {
    
    
        diff.minutes = (tot1 - tot2) % 60;
        diff.hours = (tot1 - tot2) / 60;
    }
    return diff;
}

Time Time::operator*(double n) const
{
    
    
    Time result;
    long totalminutes = hours * n * 60 + minutes * n;
    result.hours = totalminutes / 60;
    result.minutes = totalminutes % 60;
    return result;
}

void Time::show() const
{
    
    
    cout << hours << " hours, " << minutes << " minutes." << endl;
}

// 友元函数定义,不需要限定符,不需要关键字,可以使用私有成员
//Time operator*(double m, const Time & t)
//{
    
    
//    Time result;
//    long totalminutes = t.hours * m * 60 + t.minutes * m;
//    result.hours = totalminutes / 60;
//    result.minutes = totalminutes % 60;
//    return result;
//}

// operator<<( )直接访问Time对象的私有成员,所以它必须是Time类的友元。
ostream & operator<<(ostream & os, const Time & t)
{
    
    
    os << t.hours << " hours, " << t.minutes << " minutes." << endl;
    return os;
}

usemytime0.cpp

#include "mytime0.h"
int main(void)
{
    
    
    Time t1;
    Time t2(4, 20);
    Time t3;
    t3 = t2.Sum(t1);
    t3 = t2.operator+(t1);  // t3 = t1 + t2;
    Time t4;
    t4 = t3 + t2 + t1;  // + 加号两边都是类对象,调用成员函数,重载运算符+
    t4.show();
    Time t5;
    t5 = t4 - t3;       // - 减号两边都是类对象,调用成员函数,重载运算符-
    t5.show();
    Time t6;
    t6 = t5 * 3.0;      // * 左边操作数是类对象,调用成员函数,重载运算符*
    t6.show();
    t6 = 2.1 * t5;      // * 右边操作数是类对象,调用非成员友元函数,重载运算符*
    t6.show();
    cout << "t6:" << t6;// << 右边是类对象,调用非成员友元函数,重载运算符<<
    return 0;
}

11.3 Friend functions

  1. By making a function a friend of a class, you give the function the same access as a member function of the class. Can access private members of the class.
  2. If you want to overload an operator for a class with a non-class item as its first operand, you can use a friend function to reverse the order of the operands.
  3. A non-member function is not called by an object, all values ​​it uses (including the object) are explicit parameters.
  4. For the member function version, one operand is passed implicitly through the this pointer, and the other operand is passed explicitly as a function parameter;
  5. For the friend version, both operands are passed as arguments.

11.3.1 Creating friend functions

  1. The first step is to put its prototype in the class declaration and add the keyword friend before the prototype declaration:friend Time operator*(double m, const Time & t);
  2. The second step is to write the function definition. Qualifiers and friends are not required.
  3. A friend function is not a member function, so it cannot be called using the member operator, but it has the same access as a member function.
  4. Only the class declaration can determine which functions are friend functions.
// 在Time类中声明,只有类声明可以决定哪一个函数是友元
friend Time operator*(double m, const Time & t);    // 非成员友元函数
// friend Time operator*(double m, const Time & t) { return t * m;} // 内联函数,其中使用成员函数重载运算符*

// 友元函数定义,不需要限定符,不需要关键字,可以使用私有成员
Time operator*(double m, const Time & t)
{
    
    
    Time result;
    long totalminutes = t.hours * m * 60 + t.minutes * m;
    result.hours = totalminutes / 60;
    result.minutes = totalminutes % 60;
    return result;
}

// 调用
Time t5(12, 20);
Time t6;
t6 = 2.1 * t5;      // * 右边操作数是类对象,调用非成员友元函数,重载运算符*

11.3.2 Commonly used friends: Overload the << operator for output.

If you want cout << t6;to directly display the class object t6, the right side of << is the class object, then use the non-member friend function to overload the operator <<.

// 声明
friend ostream & operator<<(ostream & os, const Time & t); // 重载运算符<<

// 定义
// operator<<( )直接访问Time对象的私有成员,所以它必须是Time类的友元。
// 注意返回是一个ostream的引用
ostream & operator<<(ostream & os, const Time & t)
{
    
    
    os << t.hours << " hours, " << t.minutes << " minutes." << endl;
    return os;
}

// 调用
Time t6;
cout << "t6:" << t6; 	// << 右边是类对象,调用非成员友元函数,重载运算符<<

11.5 Overloading Revisited: A Vector Class

  1. Classes are great for representing different aspects of an entity in one object. First store multiple representations in one object; then, write class functions so that assigning a value to one representation will automatically assign values ​​to the other representations.
  2. If the method computes a new class object, consider whether you can use a class constructor to do the job. Doing this not only avoids trouble, but also ensures that new objects are created in the correct way.
  3. Because operator overloading is implemented with functions, you can overload the same operator multiple times as long as the operator function has different signatures and uses the same number of operators as the corresponding built-in C++ operator.

vector.h

#ifndef PRIMERPLUS_VERTOR_H
#define PRIMERPLUS_VERTOR_H
#include <iostream>
#include <cmath>
using namespace std;
namespace VECTOR
{
    
    
    class Vector
    {
    
    
    public:
        enum Mode {
    
    RECT, POL};
        // 外部使用POL时要加上类名称和限定符,或者声明using VECTOR::Vector;

    private:
        double x;       // 直角坐标x
        double y;       // 直角坐标y
        double mag;     // 极坐标长度
        double ang;     // 极坐标角度
        Mode mode;      // 枚举变量
        void set_mag();
        void set_ang();
        void set_x() {
    
    x = mag * cos(ang);}
        void set_y() {
    
    y = mag * sin(ang);}

    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() {
    
    mode = POL;}
        void rect_mode() {
    
    mode = RECT;}

        Vector operator+(const Vector & b) const;
        Vector operator-(const Vector & b) const;
        Vector operator-() const;           // 重载运算符-,进行取反操作
        Vector operator*(double n) const;   // 使用格式:类的对象 * 放大倍数

        friend Vector operator*(double n, const Vector & a) {
    
    return a * n;}
        friend ostream & operator<<(ostream & os, const Vector & v);
    };
}

#endif

vector.cpp

#include "vector.h"

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

    void Vector::set_mag()
    {
    
    
        mag = sqrt(x*x + y*y);
    }

    void Vector::set_ang()
    {
    
    
        if (x == 0.0 && y == 0.0)
            ang = 0;
        else
            ang = atan2(y, x);  // 弧度制
    }

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

    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 << "ERROR." << endl;
            x = y = mag = ang = 0.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 << "ERROR." << endl;
            x = y = mag = ang = 0.0;
            mode = RECT;
        }
    }

    Vector::~Vector()
    {
    
    

    }

    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); // 注意!!!这里使用 x 和 y 为前项
        // 从隐式矢量参数减去以显式参数传递的矢量
    }

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

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

    ostream & operator<<(ostream & os, const Vector & v)
    {
    
    
        if (v.mode == Vector::POL) //注意这里的POL要加上类限定符,友元函数不在类作用域
            os << "mag, nag : " << v.mag << ", " << v.ang << endl;
        else if (v.mode == Vector::RECT)
            os << "x, y : " << v.x << ", " << v.y << endl;
        else
            os << "ERROR." << endl;
        return os;
    }
}

usevector.cpp

// randwalk.cpp -- using the Vector class
#include <iostream>
#include <cstdlib>  // rand(), srand() prototypes
#include <ctime>    // time() prototype
#include "vector.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";
    cin.clear();
    while (cin.get() != '\n')
        continue;
    return 0;
}

11.6 Automatic conversions and casts of classes

The C++ language does not automatically convert incompatible types.

Conversion from parameter type to class type:

  1. A constructor that accepts only one parameter: defines a conversion from the parameter type to the class type. Can be used for both implicit and explicit conversions.
  2. If explicitsuch a constructor is keyword-qualified, it can only be used for explicit conversions.
Stonewt(double lbs);			// Stonewt类声明中的构造函数
Stonewt incognito = 275;    	// 类的自动隐式转换,将int数字转换成类的对象,创建临时对象,传递给incognito
Stonewt incognito_ = Stonewt(275); // 创建一个临时的无名的类对象,传递给incognito_

// 加关键字就不会自动类型转换,需要显示转换
explicit Stonewt(double lbs); 	
Stonewt incognito_ = Stonewt(275); // 显示转换,创建一个临时的无名的类对象,传递给incognito_

Conversions from class types to other types:

  1. C++ operator function - conversion function: can realize the conversion from class type to other types.
  2. Conversion functions are user-defined casts that can be used just like casts.
  3. If explicita conversion function is qualified with a keyword, it can only be used for explicit conversions.

How to create conversion function?

  1. To convert to the typeName type, you need to use a conversion function of this form:operator typeName();
  2. The conversion function must be a class method; it needs to be called through a class object.
  3. A conversion function cannot specify a return type; typeName indicates the type to convert to.
  4. Conversion functions cannot have parameters.
// 如果定义了从Stonewt类到double的转换函数
operator double() const;
explicit operator double() const;	// 如果加了关键字后,只能显示转换
// 编译器发现,右侧是Stonewt类型,而左侧是double类型,因此它将查看程序员是否定义了与此匹配的转换函数。
Stonewt wolfe(285.7);
double hello = wolfe;				// 隐式
double host = double (wolfe); 		// 显示,syntax #1
double thinker = (double) wolfe; 	// 显示,syntax #2

stonewt.h

#ifndef PRIMERPLUS_STONEWT_H
#define PRIMERPLUS_STONEWT_H
class Stonewt
{
    
    
private:
    // 在类里定义const常量不会在内存中保留
    enum {
    
    Lbs_per_stn = 14};    // pounds per stone
    int stone;                  // 英石
    double pds_left;            // 磅
    double pounds;              // 总磅
public:
    // explicit Stonewt(double lbs); // 加关键字explicit就不会自动隐式类型转换
    Stonewt(double lbs);        // 只有接受一个参数的构造函数才能作为转换函数。
    Stonewt(int stn, double lbs);
    Stonewt();
    ~Stonewt();
    void show_lbs() const;      // show weight in pounds format
    void show_stn() const;      // show weight in stone format

    operator int() const;             // 转换函数
    operator double() const;
};
#endif //PRIMERPLUS_STONEWT_H

stonewt.cpp

// stonewt.cpp -- Stonewt methods
#include <iostream>
using std::cout;
#include "stonewt.h"
Stonewt::Stonewt(double lbs)
{
    
    
    stone = int (lbs) / Lbs_per_stn; // integer division
    pds_left = int (lbs) % Lbs_per_stn + lbs - int(lbs);
    pounds = lbs;
}
// construct Stonewt object from stone, double values
Stonewt::Stonewt(int stn, double lbs)
{
    
    
    stone = stn;
    pds_left = lbs;
    pounds = stn * Lbs_per_stn +lbs;
}
Stonewt::Stonewt() // default constructor, wt = 0
{
    
    
    stone = pounds = pds_left = 0;
}
Stonewt::~Stonewt() // destructor
{
    
    }
// show weight in stones
void Stonewt::show_stn() const
{
    
    
    cout << stone << " stone, " << pds_left << " pounds\n";
}
// show weight in pounds
void Stonewt::show_lbs() const
{
    
    
    cout << pounds << " pounds\n";
}
// conversion functions
Stonewt::operator int() const
{
    
    
    return int (pounds + 0.5);
}
Stonewt::operator double() const
{
    
    
    return pounds;
}

usestonewt.cpp

// stone.cpp -- user-defined conversions
// compile with stonewt.cpp
#include <iostream>
using std::cout;
using std::endl;
#include "stonewt.h"
void display(const Stonewt & st, int n);
int main()
{
    
    
    // 只有接受一个参数的构造函数才能作为转换函数。
    cout << "-------------------construct function--------------------" << endl;
    Stonewt incognito = 275;    // 类的自动转换,将数字转换成类的对象,创建临时对象,传递给incognito
    Stonewt incognito_ = Stonewt(275); // 创建一个临时的无名的类对象,传递给incognito_
    Stonewt wolfe(285.7);       // 构造函数用于将double类型的值转换为Stonewt类型
    Stonewt taft(21, 8);
    cout << "The celebrity weighed ";
    incognito.show_stn();
    cout << "The detective weighed ";
    wolfe.show_stn();
    cout << "The President weighed ";
    taft.show_lbs();
    cout << "---------------------------------------" << endl;
    incognito = 276.8;          // uses constructor for conversion
    taft = 325;                 // same as taft = Stonewt(325);
    cout << "After dinner, the celebrity weighed ";
    incognito.show_stn();
    cout << "After dinner, the President weighed ";
    taft.show_lbs();
    cout << "---------------------------------------" << endl;
    display(taft, 2);
    cout << "The wrestler weighed even more.\n";
    display(422, 2);
    cout << "No stone left unearned\n";
    cout << "-------------------conversion functions--------------------" << endl;
    Stonewt poppins(9,2.8); // 9 stone, 2.8 pounds
    double p_wt = poppins; // implicit conversion
    cout << "Convert to double => ";
    cout << "Poppins: " << p_wt << " pounds.\n";
    cout << "Convert to int => ";
    cout << "Poppins: " << int (poppins) << " pounds.\n";
    return 0;
}
void display(const Stonewt & st, int n)
{
    
    
    for (int i = 0; i < n; i++)
    {
    
    
        cout << "Wow! ";
        st.show_stn();
    }
}

11.7 Summary

  1. Generally speaking, the only way to access private class members is to use class methods. C++ uses friend functions to get around this limitation. To make a function a friend, you need to declare the function in the class declaration and add the keyword before the declaration friend.
  2. C++ extends the overloading of operators, allowing custom special operator functions, which describe the relationship between specific operators and classes. Operator functions can be class member functions or friend functions (some operator functions can only be class member functions). To call an operator function, either call the function directly, or use an overloaded operator in the usual syntax.
  3. For the operator op, the format of its operator function is as follows: operatorop(argument-list), argument-list indicates the operand of the operator. If the operator function is a class member function, the first operand is the call object, which is not in the argument-list. For example, this chapter overloads addition by defining the operator +( ) member function for the Vector class. If up, right, and result are all Vector objects, you can use any of the following statements to call vector addition: result = up.operator+(right);``result = up + right;In the second statement, since the operands up and right are both of type Vector, C++ will use Vector addition definition.
  4. When the operator function is a member function, then the first operand will be the object on which the function was called. For example, in the preceding statement, the up object is the object that called the function. When defining an operator function, you must use a friend function if you want its first operand not to be a class object. This allows the operands to be passed to the function in the desired order.
  5. One of the most common operator overloading tasks is to define the << operator so that it can be used with cout to display the contents of an object. To make the ostream object the first operand, the operator function needs to be defined as a friend; to enable the redefined operator to splice with itself, the return type needs to be declared as ostream &. The following general form satisfies this requirement: however, if the class contains methods that return the values ​​of data members that need to be displayed, these methods can be used without directly accessing these members in operator<<( ). In this case, the function does not have to (and should not) be a friend.
ostream & operator<<(ostream & os, const c_name & obj)
{
    
    
    os << ... ; // display object contents
    return os;
}
  1. C++ allows specifying how to convert between classes and primitive types. First, any constructor that accepts a single argument can be used as a conversion function to convert a value of the same type as that argument to a class. C++ will automatically call the constructor if you assign a value of the same type as the parameter to the object.
    For example, suppose there is a String class that contains a constructor that takes a char * value as its only parameter, then if the bean is a String object, the following statement can be used: // converts type char * to type String. However
    bean = "pinto"; ,
    if If the keyword is added before the declaration of the constructor explicit, the constructor will only be used for explicit conversion:
    bean = String("pinto"); // converts type char * to type String explicitly
  2. To convert a class object to another type, a conversion function must be defined, indicating how to do this conversion. Conversion functions must be member functions. The prototype of the conversion function that converts the class object to the typeName type is as follows: operator typeName();Note that the conversion function has no return type and no parameters, but must return the converted value (although the return type is not declared). For example, here is a function that converts a Vector to a double:
Vector::operator double()
{
    
    
    ...
    return a_double_value;
}

11.8 Review Questions

1. Use a member function to overload the multiplication operator for the Stonewt class, which multiplies a data member with a value of type double. Note that when expressed in stones and pounds, rounds are required. That is, multiplying 10 stone 8 pounds by 2 equals 21 stone 2 pounds. (one stone equals 14 pounds)

// prototype
Stonewt operator*(double mult);

// definition - let constructor do the work
Stonewt Stonewt::operator*(double mult)
{
    
    
    return Stonewt(mult * pounds);
}

4. Use a friend function to overload the multiplication operator for the Stonewt class, which multiplies a double value with a Stone value.

// prototype
friend Stonewt operator*(double mult, const Stonewt & s);

// definetion - let constructor do the work
Stonewt operator*(double mult, const Stonewt & s)
{
    
    
    return Stonewt(mult * s.pounds);
}

2. What is the difference between a friend function and a member function?
Member functions are part of the class definition and are invoked through a specific object. A member function can implicitly access members of the calling object without using the member operator.
Friend functions are not part of the class and are therefore called direct function calls. Friend functions cannot implicitly access class members, but must use member operators on objects passed as arguments.

3. Do non-member functions have to be friends to access class members?
To access private members, it must be a friend, but to access public members, it need not be a friend.

5. Which operators cannot be overloaded?
【sizeof】【.】【.*】【::】【?:】

6. What are the restrictions when overloading operators =, ( ), [ ], and ->?
These operators must be defined using member functions.

7. Define a conversion function for the Vector class to convert the Vector class to a value of type double, which represents the length of the vector.

operator double() {
    
    return mag;}

11.9 Programming Exercises

p7.h

#ifndef __COMPLEX_0_H__
#define __COMPLEX_0_H__

#include <iostream>

using namespace std;

class complex
{
    
    
	private:
		double real;
		double imaginary;
	public:
		complex();
		complex(double r, double i);
		complex operator+(const complex &c) const;
		complex operator-(const complex &c) const;
		complex operator*(const complex &c) const;
		complex operator~() const;

		friend complex operator*(double x, const complex &c);
		friend istream &operator>>(istream &is, complex &c);
		friend ostream &operator<<(ostream &os, const complex &c);
};


#endif

p7.cpp

#include "complex0.h"

complex::complex()
{
    
    
	real = imaginary = 0.0;
}

complex::complex(double r, double i)
{
    
    
	real = r;
	imaginary = i;
}

complex complex::operator+(const complex &c) const
{
    
    
	return complex(real+c.real, imaginary+c.imaginary);
}

complex complex::operator-(const complex &c) const
{
    
    
	return complex(real-c.real, imaginary-c.imaginary);
}

complex complex::operator*(const complex &c) const
{
    
    
	return complex(real*c.real - imaginary*c.imaginary, real*c.imaginary + imaginary*c.real);
}

complex complex::operator~() const
{
    
    
	return complex(real, -imaginary);
}

complex operator*(double x, const complex &c)
{
    
    
	return complex(x*c.real, x*c.imaginary);
}

istream &operator>>(istream &is, complex &c)
{
    
    
	is >> c.real >> c.imaginary;
	return is;
}

ostream &operator<<(ostream &os, const complex &c)
{
    
    
	os << "real = " << c.real << ", imaginary = " << c.imaginary << endl;
	return os;
}

mainp7.cpp

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

using namespace std;

int main(void)
{
    
    
	complex a(3.0, 4.0);
	complex c;
	cout << "Enter a complex number (q to quit): \n";

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

	return 0;
}

Guess you like

Origin blog.csdn.net/qq_39751352/article/details/126884382