クラスを使用したC ++ノート(9)の再学習

1.演算子のオーバーロード

以前、C ++関数のポリモーフィズムまたは関数のオーバーロードと呼ばれるものを紹介しました。演算子のオーバーロードはC ++ポリモーフィズムの形式であり、オーバーロードの概念を演算子に拡張して、C ++演算子に複数の意味を与えることができます。

実際、多くのC ++演算子はオーバーロードされています。たとえば、*演算子はアドレスに使用されますが、2つの数値を乗算するためにも使用できます。C ++では、演算子のオーバーロードをユーザー定義の型に拡張できます。たとえば、配列追加クラスなどをオーバーロードできます。ただし、オーバーロードされた演算子は有効なC ++演算子である必要があります。たとえば、「@」を演算子としてオーバーロードすることはできません

1.1オーバーロードされた加算の例

以下は、クラスの追加とオーバーロードです。

my_class.hコードは次のとおりです

#ifndef MY_CLASS_H
#define MY_CLASS_H

class my_class
{
    
    
public:
    my_class();
    my_class(int h, int m = 0);
    my_class operator+(const my_class& t) const;//加法重载
    void show();
private:
    int hours;
    int minutes;
};
#endif // MY_CLASS_H

my_class.cppコードは次のとおりです

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

my_class::my_class()
{
    
    
    hours = minutes = 0;
}
my_class::my_class(int h, int m)
{
    
    
    hours = h;
    minutes = m;
}
my_class my_class::operator +(const my_class& t) const
{
    
    
    my_class sum;
    sum.minutes = minutes + t.minutes;
    sum.hours = hours + t.hours + sum.minutes/60;
    sum.minutes %= 60;
    return sum;
}
void my_class::show()
{
    
    
    cout<<"After operator +: \n";
    cout<<hours<<" : "<<minutes<<endl;
}

主な機能コード

#include"my_class.h"
int main()
{
    
    
    my_class time1(2, 40);//2小时40分
    my_class time2(3, 30);//3小时30分
    my_class total;

    total = time1 + time2;//重载+,调用
    total.show();
}

出力:

After operator +: 
6 : 10

上記の式は、3つのオブジェクトに追加することもできます。これは、追加するたびに1つのオブジェクトが返されるためです。

1.2過負荷制限

  • オーバーロードされた演算子の少なくとも1つ以上のオペランドはユーザー定義です。たとえば、double型はユーザー定義ではないため、加算演算子をdouble値の合計としてオーバーロードすることはできません。
  • 演算子がオーバーロードされている場合、演算子の元の構文規則に違反したり、演算子の優先順位を変更したりすることはできません。これは、元のオペレータールールを保証するためです。
  • 新しい演算子を作成できません。
  • 次の演算子はオーバーロードできません
  1. sizeof演算子
  2. " "メンバー演算子
  3. スコープ演算子::
  4. 条件付き演算子?
  5. RTTI演算子typeid
  6. const_cast、dynamic_cast、reinterpret_cast、およびstatic_castのキャスト演算子。

ここに画像の説明を挿入
ここに画像の説明を挿入

1.3単一のオブジェクトの操作

オブジェクトに倍数を掛けるなど、単一のオブジェクトを操作する演算子のオーバーロードを作成します。そのプロトタイプは次のとおりです。

 my_class operator* (double n) const;

定義:

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

転送:

total = total * 1.5;//对象扩大1.5倍
total.show();

2.フレンド機能

2.1単一オブジェクトの完璧な操作

パブリックメソッドを使用してプライベートメンバーにアクセスするだけでなく、友達からアクセスすることもできます。フレンドには、フレンド関数、フレンドクラス、フレンドメンバー関数の3種類があります。ここではフレンド関数のみを紹介します。他の2つについては後で説明します。

前のサンプルコードで、オブジェクトに拡張係数を掛ける方法は次のとおりです。

A = B *2.75;

これは実際には次と同等です。

A = B.operator*(2.75);

しかし、A = 2.75 * Bに遭遇した場合、どのように対処すればよいでしょうか。乗算の左側は呼び出し元のオブジェクトである必要があり、2.75はオブジェクトではないため、コンパイラーはメンバー関数呼び出しを使用して式を置き換えることはできません。

そのため、非メンバー関数呼び出しが表示されます。プライベートメンバーにアクセスするために、フレンド関数が表示されます。

friend my_class operator* (double m, const my_class& t);

オーバーロードされた演算子を定義する場合、スコープ修飾子を使用する必要はありません。また、それらを定義するときにフレンドを使用する必要もありません。

my_class operator *(double m, const my_class&t)
{
    
    
    my_class result;
    long totalMinutes = t.hours * m * 60 + t.minutes * m;//注意需要使用t.hours
    result.hours = totalMinutes/60;
    result.minutes = totalMinutes%60;
    return result;
}

主な関数呼び出し:

    total = 2 * total;
    total.show();

上記のフレンド関数を変更することもできます。

my_class operator* (double m, const my_class& t)
{
    
    
	return t * m;
}

2.2一般的に使用される友達:オーバーロードされた<<演算子

(1)出力オブジェクト

実際、<<演算子は何度もオーバーロードされており、最初はCおよびC ++演算子の少し左シフトでした。その後、ostreamクラスはそれをオーバーロードし、出力ツールとして使用しました。オブジェクトタイプの出力など、オーバーロードすることもできます。

my_classがオーバーロードに使用される場合、そのオブジェクトは最初のオペランドであり、出力形式はtime << coutになります。これは非常に厄介になります。だから私たちは友達を使って解決します。

friend void operator << (std::ostream& os, const my_class& t);

プロトタイプから、coutが最初の入力オブジェクトであり、my_classが2番目のオブジェクトであることがわかります。my_classのデータメンバーにアクセスする必要があるため、ostreamのフレンドではなくmy_classのフレンド関数を使用する必要があります。 coutのエイリアスを使用します。その定義形式は次のとおりです。

void operator << (std::ostream & os, const my_class& t)
{
    
    
    os << t.hours <<" hours," <<t.minutes<<" minutes";
}

次に、<<出力オブジェクトを通常どおりに使用できます。

cout<<total;

(2)従来のカウトと組み合わせて使用

上記のフォームは、次のような操作には使用できません。

cout <<"Trip time:" <<total<<endl;

coutは左から右に出力されることがわかっているので、cout << x << y;はそれがと同等であることを意味します

(cout << x)<<y;

したがって、ostreamオブジェクトへの参照を返すために<<演算子を要求する必要があります。つまり、(cout << x)自体はostreamオブジェクトのcoutであるため、左側に配置できます。そのため、フレンド関数を変更し続けます。

//原型修改为:
friend std::ostream& operator << (std::ostream& os, const my_class& t);
//定义修改为:
std::ostream& operator << (std::ostream & os, const my_class& t)
{
    
    
    os << t.hours <<" hours," <<t.minutes<<" minutes";
    return os;
}

2.3オーバーロードされた演算子:メンバー関数または非メンバー関数として

オーバーロードされた演算子の場合、非メンバー関数フォームは、プライベートメンバーにアクセスできるため、通常、フレンド関数フォームを使用します。オブジェクト追加演算子はオーバーロードされており、次の形式でも同じ効果があります。

my_class operator+ (const my_class& t) const;//成员函数形式
friend my_class operator* (const my_class& t1, const my_class& t2);//友元函数形式

加算演算子には2つのオペランドが必要です。メンバー関数バージョンの場合、一方のオペランドはthisポインターを介して暗黙的に渡され、もう一方のオペランドは関数パラメーターとして明示的に渡されます。フレンドバージョンの場合、両方のオペランドがパラメーターとして渡されます。

3.クラスの自動変換と強制型変換

まず、C ++が組み込み型変換を処理する方法を確認しましょう。2つの標準型に互換性がある場合、C ++は値を受信変数の型に自動的に変換します。例えば

long count = 8;//自动将8转换为long
double time = 11;//自动将11转换为double
int side = 3.33;//自动将3.33转换为int

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

int *p = 10;//不能进行转换,错误!!!

しかし、C ++では、強制を使用して10をintポインター型にキャストし、ポインターをアドレス10に設定できます。この変換が意味をなすかどうかは別の問題です。

int * p  = (int *) 10;

3.1オブジェクトの自動暗黙変換

そのようなコンストラクターがある場合:

Stonewt::Stonewt(double lbs)
{
    
    
    stone = int(lbs) / Lbs_per_stn;
    pds_left = int(lbs) % Lbs_per_stn + lbs - int(lbs);
    pounds = lbs;
}

次に、次のようにコンストラクターを呼び出すことができます。

Stonewt myCat(19.6);

暗黙の変換方法もあります。

Stonewt myCat;
myCat = 19.6;//隐式转换

3つ以上のパラメーターコンストラクターがある場合、暗黙的な変換は使用できません。この種の暗黙的な変換が必要ない場合は、コンストラクターを定義するときにキーワードexplicitを追加して、この自動機能をオフにすることができます。

explicit Stonewt(double lbs);//不允许隐式转换!!!

ただし、明示的な変換、つまり明示的な強制を実行することもできます。

Stonewt myCat;
myCat = Stonewt(19.6);
//或者
myCat = (Stonewt) 19.6;

3.2変換機能

上記はdoubleをStonewtタイプに変換できますが、Stonewtはdoubleタイプに変換できますか?ここでは、C ++の特殊な演算子関数変換関数を使用する必要があります。

変換関数はユーザー定義の強制型変換であり、強制型変換のように使用できます。定義方法:

operator typeName();//typeName为要转换的类型

次の点に注意してください:

  • 変換関数はクラスメソッドである必要があります。
  • 変換関数は戻り値の型を指定できません。
  • 変換関数にパラメーターを含めることはできません。

クラスでintおよびdouble変換関数を定義します。

operator double()const;//转换为double类型
operator int() const;//转换为int类型

彼らの実現:

Stonewt::operator double()const
{
    
    
    return pounds;
}
Stonewt::operator int()const
{
    
    
    return int (pounds + 0.5);//pounds为类的数据成员,也就是对象的数据成员
}

main関数で使用します:

    int x = int(myCat);
    //或者
    x = myCat;
    cout<<x<<endl;

変換関数が1つだけ定義されている場合は、あいまいさを引き起こす他の変換関数がないため、cout出力オブジェクトと連携することもできます(自動変換)。ただし、変換関数が3つ以上あると、あいまいさが生じ、コンパイルエラーが発生します。

cout << myCat<<endl;//如果没有歧义的情况下,可以使用
long gone = myCat;//如果没有歧义的情况下,可以使用

C ++ 11では、変換関数に明示的を使用します。この場合、変換関数を明示的に使用する必要があります。もちろん、読者は変換関数を使用する代わりに、通常のメンバー関数を自分で作成することもできます。

3.3変換機能とフレンド機能

以下では、Stonewtクラスの加算演算子をオーバーロードします。メンバー関数またはフレンド関数を使用して、次のことを実現できます。

メンバー関数の実装:

Stonewt Stonewt::operator+ (const Stonewt& st)const
{
    
    
	double pds = pounds + st.pounds;
	Stonewt sum(pds);//普通构造函数
	return sum;
}

フレンド機能の実装:

Stonewt operator+ (const Stonewt& st1, const Stonewt& st2)
{
    
    
	double pds = st1.pounds + st2.pounds;
	Stonewt sum(pds);//普通构造函数
	return sum;
}

加算は上記の方法で実行できます。

Stonewt stone1(9, 12);
Stonewt stone2(12,8);
Stonewt total;
total = stone1 + stone2;

Stonewt(double)コンストラクターが提供されている場合は、次のように実行できます。

Stonewt stone1(9, 12);
double stoneDouble = 12.8;
Stonewt total;
total = stone1 + stoneDouble;//必须是stone1在前面

ただし、フレンド関数のみが次のように動作できます(メンバー関数の場合、最初のパラメーターはオブジェクトである必要があります)。

Stonewt stone1(9, 12);
double stoneDouble = 12.8;
Stonewt total;
total = stoneDouble + stone1;//stone1在后面,不允许!!!

したがって、オブジェクトとdoubleの加算には2つの選択肢があります。1つ目は、フレンド関数として加算をオーバーロードし、Stonewt(double)コンストラクターにdouble型パラメーターをStonewt型パラメーターに変換させることです。2つ目は、前述のdouble型のオーバーロードの追加です。最初のメソッドはコードが少なく、エラーの可能性も低くなりますが、変換コンストラクターが毎回呼び出されるため、時間とメモリのオーバーヘッドが増加します。2番目の方法はコードが多く、プログラマーはより多くの作業を行いますが、計算速度は速くなります。

達成するための2番目の方法:

//成员函数与友元函数的结合方式实现加法重载
Stonewt operator+(double x);
friend Stonewt operator+(double x, Stonewt& s);

概要ディレクトリ
前:(8)オブジェクトとクラス
次:(10)クラスと動的メモリ割り当て


記事の参照:「C ++ Primer PlusSixthEdition」

おすすめ

転載: blog.csdn.net/QLeelq/article/details/111058664