【C++入門Plus】第11章 クラスの使い方

これらのスキルは、頻繁に使用しない限り、日常の仕事にはまったく関係ない可能性があります。

11.1 演算子のオーバーロード

  1. C++ は、オペランドの数と型に基づいて、どの演算を使用するかを決定します。
  2. * 演算子をアドレスに適用すると、そのアドレスに値が格納されますが、2 つの数値に適用すると、その積が求められます。
  3. C++ では、演算子のオーバーロードをユーザー定義型に拡張できます。たとえば、+ を使用して 2 つのオブジェクトを追加できます。
  4. 演算子をオーバーロードするには、演算子関数と呼ばれる特別な関数形式が使用されます。operatorop(argument-list)
  5. 演算子 + ( ) は + 演算子をオーバーロードし、演算子( ) は演算子をオーバーロードします。[ ] は配列のインデックス演算子です。
district2 = sid + sara;
// 编译器发现,这三个操作数有一个是用户自定义的类型,
// 因此使用相应的运算符函数替换上述运算符:
district2 = sid.operator+(sara);
// 隐式地使用sid(因为它调用了方法)
// 显式地使用 sara对象(因为它被作为参数传递),来计算总和,并返回这个值。

11.2 計算時間: 演算子のオーバーロードの例

  1. パラメータを参照として宣言する目的は、効率化を図るためです。Time オブジェクトを値で渡す場合、コードは同じように機能しますが、参照することで高速になり、使用するメモリが少なくなります。
  2. 戻り値の型 Time を使用するということは、プログラムが sum を削除する前にコピーを作成し、呼び出し関数がそのコピーを取得することを意味します。
  3. ローカル変数または一時オブジェクトへの参照を返さないでください。関数が実行されると、ローカル変数と一時オブジェクトが消え、参照は存在しないデータを指すようになります。

11.2.1 オーバーロードされた演算子の制限事項

  1. オーバーロードされた演算子には、ユーザー定義型のオペランドが少なくとも 1 つ必要です。これにより、ユーザーは標準型の演算子をオーバーロードできなくなります。
  2. 演算子を使用する場合、演算子の元の構文規則に違反することはできません。たとえば、モジュロ演算子 (%) をオーバーロードして 1 つのオペランドを取ることはできません。
  3. 演算子の優先順位は変更できません。
  4. 新しいオペレータを作成できません。たとえば、べき乗を表すために演算子 **( ) 関数を定義することはできません。
  5. 一部の演算子はメンバー関数を介してのみオーバーロードできます。= 代入演算子。( ) 関数呼び出し演算子。[ ] 添字演算子。-> ポインタを介してクラス メンバーにアクセスするための演算子。
  6. 一部の演算子はオーバーロードできません。sizeof 演算子。.会員制運営者。. * メンバー ポインター演算子。:: スコープ解決演算子。?: 条件演算子。typeid RTTI 演算子。const_cast キャスト演算子。Dynamic_cast キャスト演算子。reinterpret_cast キャスト演算子。static_cast キャスト演算子。

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 フレンド機能

  1. 関数をクラスのフレンドにすると、その関数にクラスのメンバー関数と同じアクセス権が与えられます。クラスのプライベート メンバーにアクセスできます。
  2. 非クラス項目を最初のオペランドとしてクラスの演算子をオーバーロードする場合は、フレンド関数を使用してオペランドの順序を逆にすることができます。
  3. 非メンバー関数はオブジェクトによって呼び出されず、使用されるすべての値 (オブジェクトを含む) は明示的なパラメーターです。
  4. メンバー関数バージョンの場合、1 つのオペランドは this ポインターを介して暗黙的に渡され、もう 1 つのオペランドは関数パラメーターとして明示的に渡されます。
  5. フレンド バージョンの場合、両方のオペランドが引数として渡されます。

11.3.1 フレンド機能の作成

  1. 最初のステップは、そのプロトタイプをクラス宣言に配置し、プロトタイプ宣言の前にキーワード friends を追加することです。friend Time operator*(double m, const Time & t);
  2. 2 番目のステップは、関数定義を作成することです。予選通過者や友人は必要ありません。
  3. フレンド関数はメンバー関数ではないため、メンバー演算子を使用して呼び出すことはできませんが、メンバー関数と同じアクセス権があります。
  4. どの関数がフレンド関数であるかを決定できるのはクラス宣言だけです。
// 在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 よく使用される友人: 出力用に << 演算子をオーバーロードします。

cout << t6;<< の右側がクラス オブジェクトであるクラス オブジェクト t6 を直接表示したい場合は、非メンバーのフレンド関数を使用して演算子 << をオーバーロードします。

// 声明
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 オーバーロードの再考: ベクトル クラス

  1. クラスは、1 つのオブジェクト内のエンティティのさまざまな側面を表現するのに最適です。まず複数の表現を 1 つのオブジェクトに格納し、次に、1 つの表現に値を代入すると、他の表現にも自動的に値が割り当てられるようにクラス関数を作成します。
  2. メソッドが新しいクラス オブジェクトを計算する場合は、クラス コンストラクターを使用してそのジョブを実行できるかどうかを検討してください。これを行うと、トラブルが回避されるだけでなく、新しいオブジェクトが正しい方法で作成されるようになります。
  3. 演算子のオーバーロードは関数で実装されるため、演算子関数のシグネチャが異なり、対応する組み込み C++ 演算子と同じ数の演算子を使用する限り、同じ演算子を複数回オーバーロードできます。

ベクトル.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

ベクトル.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 クラスの自動変換とキャスト

C++ 言語は、互換性のない型を自動的に変換しません。

パラメータ型からクラス型への変換:

  1. パラメータを 1 つだけ受け入れるコンストラクタ: パラメータ型からクラス型への変換を定義します。暗黙的変換と明示的変換の両方に使用できます。
  2. このようなコンストラクターがキーワード修飾されている場合explicit、明示的な変換にのみ使用できます。
Stonewt(double lbs);			// Stonewt类声明中的构造函数
Stonewt incognito = 275;    	// 类的自动隐式转换,将int数字转换成类的对象,创建临时对象,传递给incognito
Stonewt incognito_ = Stonewt(275); // 创建一个临时的无名的类对象,传递给incognito_

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

クラス型から他の型への変換:

  1. C++演算子関数 - 変換関数: クラス型から他の型への変換を実現できます。
  2. 変換関数は、キャストと同じように使用できるユーザー定義のキャストです。
  3. explicit変換関数がキーワードで修飾されている場合、その関数は明示的な変換にのみ使用できます。

変換関数を作成するにはどうすればよいですか?

  1. typeName 型に変換するには、次の形式の変換関数を使用する必要があります。operator typeName();
  2. 変換関数はクラス メソッドである必要があり、クラス オブジェクトを通じて呼び出す必要があります。
  3. 変換関数では戻り値の型を指定できません。typeName は変換先の型を示します。
  4. 変換関数にはパラメーターを含めることはできません。
// 如果定义了从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

ストーンウト

#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

ストーンウト.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 概要

  1. 一般に、プライベート クラス メンバーにアクセスする唯一の方法は、クラス メソッドを使用することです。C++ ではフレンド関数を使用してこの制限を回避します。関数をフレンドにするには、クラス宣言で関数を宣言し、宣言の前にキーワードを追加する必要がありますfriend
  2. C++ は演算子のオーバーロードを拡張し、特定の演算子とクラスの間の関係を記述するカスタムの特殊な演算子関数を許可します。演算子関数はクラス メンバー関数またはフレンド関数にすることができます (一部の演算子関数はクラス メンバー関数にしかなれません)。演算子関数を呼び出すには、関数を直接呼び出すか、通常の構文でオーバーロードされた演算子を使用します。
  3. 演算子 op の場合、その演算子関数の形式は次のとおりです。operatorop(argument-list)、argument-list は演算子のオペランドを示します。演算子関数がクラス メンバー関数である場合、最初のオペランドは呼び出しオブジェクトであり、これは引数リストにありません。たとえば、この章では、Vector クラスの演算子 +( ) メンバー関数を定義することで加算をオーバーロードします。up、right、および result がすべて Vector オブジェクトである場合、次のステートメントのいずれかを使用してベクトル加算を呼び出すことができます。 2 番目のステートメントでは、result = up.operator+(right);``result = up + right;オペランド up と right が両方とも Vector 型であるため、C++ はベクトル加算定義を使用します。
  4. 演算子関数がメンバー関数の場合、最初のオペランドは関数が呼び出されたオブジェクトになります。たとえば、前のステートメントでは、up オブジェクトは関数を呼び出したオブジェクトです。演算子関数を定義するとき、その最初のオペランドをクラス オブジェクトにしない場合は、フレンド関数を使用する必要があります。これにより、オペランドを希望の順序で関数に渡すことができます。
  5. 最も一般的な演算子オーバーロード タスクの 1 つは、オブジェクトの内容を表示するために cout で使用できるように << 演算子を定義することです。ostream オブジェクトを最初のオペランドにするには、演算子関数をフレンドとして定義する必要があります。再定義された演算子をそれ自体と結合するには、戻り値の型を ostream & として宣言する必要があります。次の一般的な形式は、この要件を満たします。ただし、クラスに、表示する必要があるデータ メンバーの値を返すメソッドが含まれている場合、これらのメソッドは、operator<<() でこれらのメンバーに直接アクセスせずに使用できます。この場合、関数はフレンドである必要はありません (また、そうすべきではありません)。
ostream & operator<<(ostream & os, const c_name & obj)
{
    
    
    os << ... ; // display object contents
    return os;
}
  1. C++ では、クラスとプリミティブ型の間で変換する方法を指定できます。まず、単一の引数を受け入れるコンストラクターは、その引数と同じ型の値をクラスに変換する変換関数として使用できます。パラメーターと同じ型の値をオブジェクトに割り当てると、C++ は自動的にコンストラクターを呼び出します。
    たとえば、唯一のパラメータとして char * 値を取るコンストラクタを含む String クラスがあるとします。Bean が String オブジェクトの場合は、次のステートメントを使用できます。 // char * 型を String 型に変換します。ただし
    bean = "pinto";
    キーワードがコンストラクターの宣言の前に追加された場合explicit、コンストラクターは明示的な変換にのみ使用されます。
    bean = String("pinto"); // char * 型を String 型に明示的に変換します。
  2. クラス オブジェクトを別の型に変換するには、この変換を行う方法を示す変換関数を定義する必要があります。変換関数はメンバー関数である必要があります。クラス オブジェクトを typeName 型に変換する変換関数のプロトタイプは次のとおりです。operator typeName();変換関数には戻り値の型もパラメーターもありませんが、(戻り値の型は宣言されていませんが) 変換された値を返さなければならないことに注意してください。たとえば、Vector を double に変換する関数を次に示します。
Vector::operator double()
{
    
    
    ...
    return a_double_value;
}

11.8 復習の質問

1. メンバー関数を使用して、Stonewt クラスの乗算演算子をオーバーロードします。この演算子は、データ メンバーと double 型の値を乗算します。ストーンとポンドで表す場合は四捨五入が必要であることに注意してください。つまり、10 ストーン 8 ポンドに 2 を掛けると、21 ストーン 2 ポンドとなります。(1 石は 14 ポンドに相当します)

// prototype
Stonewt operator*(double mult);

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

4. フレンド関数を使用して、Stonewt クラスの乗算演算子をオーバーロードします。この演算子は、double 値と Stone 値を乗算します。

// 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. フレンド機能とメンバー機能の違いは何ですか?
メンバー関数はクラス定義の一部であり、特定のオブジェクトを通じて呼び出されます。メンバー関数は、メンバー演算子を使用せずに、呼び出し元オブジェクトのメンバーに暗黙的にアクセスできます。
フレンド関数はクラスの一部ではないため、直接関数呼び出しと呼ばれます。フレンド関数は暗黙的にクラス メンバーにアクセスできませんが、引数として渡されたオブジェクトに対してメンバー演算子を使用する必要があります。

3. クラスメンバーにアクセスするには、非メンバー関数がフレンドである必要がありますか?
プライベート メンバーにアクセスするには友人である必要がありますが、パブリック メンバーにアクセスするには友人である必要はありません。

5. オーバーロードできない演算子はどれですか?
【のサイズ】【。】【。*】【::】【?:】

6. 演算子 =、( )、[ ]、および -> をオーバーロードする場合の制限は何ですか?
これらの演算子はメンバー関数を使用して定義する必要があります。

7。Vector クラスの変換関数を定義して、Vector クラスをベクトルの長さを表す double 型の値に変換します。

operator double() {
    
    return mag;}

11.9 プログラミング演習

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;
}

おすすめ

転載: blog.csdn.net/qq_39751352/article/details/126884382