C++ では、演算子のオーバーロードはコンパイル時のポリモーフィズムです。これは、C++ の既存の演算子に、元の意味を変えずに特別な意味を与えるというアイデアです。
ベースバンドとブロードバンド
この記事では、C++ での演算子のオーバーロードについて例を挙げてさらに説明し、C++ でオーバーロードできる演算子とオーバーロードできない演算子を確認します。
C++ 演算子のオーバーロード
C++ には、演算子にデータ型の特別な意味を与える機能があり、この機能は演算子のオーバーロードとして知られています。演算子のオーバーロードはコンパイル時のポリモーフィズムです。たとえば、String のようなクラスで演算子「+」をオーバーロードすると、+ を使用するだけで 2 つの文字列を連結できます。算術演算子がオーバーロードされる可能性のある他のクラス例には、複素数、分数、大きな整数などがあります。
例:
int a; float b,sum; sum = a + b;>
ここで、変数 a と b は、組み込みデータ型である int 型と float 型です。したがって、加算演算子「+」を使用すると、a と b の内容を簡単に加算できます。これは、加算演算子 + が組み込みデータ型の変数のみを追加するように事前定義されているためです。
実装:
C++
// C++ Program to Demonstrate the> // working/Logic behind Operator> // Overloading> class> A {> >statements;> };> int> main()> {> >A a1, a2, a3;> >a3 = a1 + a2;> >return> 0;> }> |
>
>
この例では、クラス A 型の 3 つの変数 a1、a2、a3 があります。ここでは、+ 演算子を使用して、ユーザー定義型、つまりクラス A 型の 2 つのオブジェクト a1 と a2 を追加しようとしています。加算演算子 + は組み込みデータ型でのみ動作するように事前定義されているため、これは許可されません。ただし、ここではクラス A はユーザー定義型であるため、コンパイラはエラーを生成します。ここで、演算子のオーバーロードの概念が登場します。
ここで、ユーザーが演算子 + に 2 つのクラス オブジェクトを追加したい場合、ユーザーは 2 つのクラス オブジェクトを追加するように + 演算子の意味を再定義する必要があります。これは、演算子のオーバーロードの概念を使用して行われます。したがって、演算子のオーバーロードの背後にある主なアイデアは、クラス変数またはクラス オブジェクトで C++ 演算子を使用することです。演算子の意味を再定義しても、実際には元の意味は変わりません。代わりに、既存のものに加えて追加の意味が与えられています。
C++ での演算子のオーバーロードの例
C++
私たちの中にはいくつの都市があるでしょうか
// C++ Program to Demonstrate> // Operator Overloading> #include> using> namespace> std;> class> Complex {> private>:> >int> real, imag;> public>:> >Complex(>int> r = 0,>int> i = 0)> >{> >real = r;> >imag = i;> >}> >// This is automatically called when '+' is used with> >// between two Complex objects> >Complex operator+(Complex>const>& obj)> >{> >Complex res;> >res.real = real + obj.real;> >res.imag = imag + obj.imag;> >return> res;> >}> >void> print() { cout << real <<>' + i'> << imag <<>'
'>; }> };> int> main()> {> >Complex c1(10, 5), c2(2, 4);> >Complex c3 = c1 + c2;> >c3.print();> }> |
>
>出力
12 + i9>
演算子関数と通常の関数の違い
演算子関数は通常の関数と同じです。唯一の違いは、演算子関数の名前が常に 演算子キーワード その後に演算子の記号が続き、対応する演算子が使用されると演算子関数が呼び出されます。
例
C++
#include> using> namespace> std;> class> Complex {> private>:> >int> real, imag;> public>:> >Complex(>int> r = 0,>int> i = 0)> >{> >real = r;> >imag = i;> >}> >void> print() { cout << real <<>' + i'> << imag << endl; }> >// The global operator function is made friend of this> >// class so that it can access private members> >friend> Complex operator+(Complex>const>& c1,> >Complex>const>& c2);> };> Complex operator+(Complex>const>& c1, Complex>const>& c2)> {> >return> Complex(c1.real + c2.real, c1.imag + c2.imag);> }> int> main()> {> >Complex c1(10, 5), c2(2, 4);> >Complex c3> >= c1> >+ c2;>// An example call to 'operator+'> >c3.print();> >return> 0;> }> |
>
>出力
12 + i9>
すべての演算子をオーバーロードすることはできますか?
一部を除いて、ほとんどすべての演算子はオーバーロードできます。以下は、オーバーロードできない演算子のリストです。
sizeof typeid Scope resolution (::) Class member access operators (.(dot), .* (pointer to member operator)) Ternary or conditional (?:)>
C++ でオーバーロードできる演算子
過負荷になる可能性があります
単項演算子 二項演算子 特殊演算子 ([ ]、() など)
ただし、その中にはオーバーロードできない演算子もいくつかあります。彼らです
スコープ解決演算子 (: メンバー選択演算子 * によるメンバー選択
メンバー変数へのポインタ
- 条件演算子 (? Sizeof 演算子 sizeof()
| オーバーロードできる演算子 | 例 |
|---|---|
| 二項演算 | +、-、*、/、% |
| 単項演算 | +、-、++、— |
| 割り当て | =、+=、*=、/=、-=、%= |
| ビットごと | &、 | 、<>、~、^ |
| 逆参照 | (->) |
| 動的なメモリ割り当て、 割り当て解除 | 新規、削除 |
| 添字 | [ ] |
| 関数呼び出し | () |
| 論理的 | &、 | |、! |
| 関連した | >、<、==、= |
上記の演算子をオーバーロードできないのはなぜですか?
1. 演算子のサイズ
これは、オペランドとして入力されたオブジェクトまたはデータ型のサイズを返します。これはコンパイラによって評価され、実行時に評価することはできません。オブジェクトの配列内のポインターの適切なインクリメントは、暗黙的に sizeof 演算子に依存します。オーバーロードを使用して意味を変更すると、言語の基本的な部分が崩壊してしまいます。
2. typeid 演算子
これにより、CPP プログラムは、ポインターまたは参照によって参照されるオブジェクトの実際に派生した型を復元できるようになります。この演算子にとって重要なのは、型を一意に識別することです。ユーザー定義型を別の型のように「見せたい」場合は、ポリモーフィズムを使用できますが、typeid 演算子の意味は変更しない必要があります。変更しないと、重大な問題が発生する可能性があります。
3. スコープ解決 (::) 演算子
これは、名前空間を指定することで、識別子が参照するコンテキストを識別して指定するのに役立ちます。これは実行時に完全に評価され、値ではなく名前に対して機能します。スコープ解決のオペランドはデータ型を持つノート式であり、CPP にはオーバーロードされた場合にそれらをキャプチャするための構文がありません。したがって、この演算子をオーバーロードすることは構文的に不可能です。
4. クラス メンバーのアクセス演算子 (.(ドット )、.* (メンバー演算子へのポインター))
クラス メンバー アクセス演算子の重要性と暗黙的な使用は、次の例から理解できます。
例:
Javaの歴史
C++
// C++ program to demonstrate operator overloading> // using dot operator> #include> using> namespace> std;> class> ComplexNumber {> private>:> >int> real;> >int> imaginary;> public>:> >ComplexNumber(>int> real,>int> imaginary)> >{> >this>->実数 = 実数;>>' ->虚数 = 虚数;>> >}> >void> print() { cout << real <<>' + i'> << imaginary; }> >ComplexNumber operator+(ComplexNumber c2)> >{> >ComplexNumber c3(0, 0);> >c3.real =>this>->実数 + c2.real;>>' this>->imaginary + c2.imaginary;>> >return> c3;> >}> };> int> main()> {> >ComplexNumber c1(3, 5);> >ComplexNumber c2(2, 4);> >ComplexNumber c3 = c1 + c2;> >c3.print();> >return> 0;> }> |
>
>出力
5 + i9>
説明:
ステートメント ComplexNumber c3 = c1 + c2;は内部的に ComplexNumber c3 = c1.operator+ (c2); として変換されます。演算子関数を呼び出すため。引数 c1 は、次のメソッドを使用して暗黙的に渡されます。 「。」 オペレーター。次のステートメントでも、ドット演算子を使用してメンバー関数 print にアクセスし、引数として c3 を渡します。
さらに、これらの演算子は値ではなく名前にも作用し、それらをオーバーロードするための (構文上) 規定はありません。
5. 三項演算子または条件演算子 (?:)
三項演算子または条件演算子は、if-else ステートメントの短縮表現です。演算子では、条件式の真偽値のみに基づいて true/false 式が評価されます。
conditional statement ? expression1 (if statement is TRUE) : expression2 (else)>
定義を使用して ABC というクラスの三項演算子をオーバーロードする関数
ABC operator ?: (bool condition, ABC trueExpr, ABC falseExpr);>
式のうち 1 つだけが評価されることを保証できません。したがって、三項演算子をオーバーロードすることはできません。
演算子のオーバーロードに関する重要なポイント
1) 演算子のオーバーロードが機能するには、少なくとも 1 つのオペランドがユーザー定義のクラス オブジェクトである必要があります。
Javaのリスト
2) 代入演算子: コンパイラは、すべてのクラスでデフォルトの代入演算子を自動的に作成します。デフォルトの代入演算子は、右側のすべてのメンバーを左側に代入し、ほとんどの場合に正常に機能します (この動作はコピー コンストラクターと同じです)。詳細については、こちらを参照してください。
3) 変換演算子: ある型を別の型に変換するために使用できる変換演算子を作成することもできます。
例:
C++
// C++ Program to Demonstrate the working> // of conversion operator> #include> using> namespace> std;> class> Fraction {> private>:> >int> num, den;> public>:> >Fraction(>int> n,>int> d)> >{> >num = n;> >den = d;> >}> >// Conversion operator: return float value of fraction> >operator>float>()>const> >{> >return> float>(num) />float>(den);> >}> };> int> main()> {> >Fraction f(2, 5);> >float> val = f;> >cout << val <<>'
'>;> >return> 0;> }> |
>
>出力
0.4>
オーバーロードされた変換演算子はメンバー メソッドである必要があります。他の演算子は、メンバー メソッドまたはグローバル メソッドのいずれかになります。
4) 単一の引数で呼び出すことができるコンストラクターはすべて、変換コンストラクターとして機能します。つまり、構築されるクラスへの暗黙的な変換にも使用できます。
例:
itn への文字列
C++
// C++ program to demonstrate can also be used for implicit> // conversion to the class being constructed> #include> using> namespace> std;> class> Point {> private>:> >int> x, y;> public>:> >Point(>int> i = 0,>int> j = 0)> >{> >x = i;> >y = j;> >}> >void> print()> >{> >cout <<>'x = '> << x <<>', y = '> << y <<>'
'>;> >}> };> int> main()> {> >Point t(20, 20);> >t.print();> >t = 30;>// Member x of t becomes 30> >t.print();> >return> 0;> }> |
>
>出力
x = 20, y = 20 x = 30, y = 0>
演算子のオーバーロードに関するクイズ