2009-03-31 8 views
3

私はC++を学んでいますが、2つの異なる型のインスタンスで動作するバイナリ演算子を作成する好ましい方法についていくつかの洞察を得ることができるのだろうかと思いました。異なるタイプの対称2項演算子

class A; 
class B; 

class A 
{ 
    private: 
     int x; 

    public: 
     A(int x); 

     int getX() const; 

     int operator + (const B& b); 
}; 


class B 
{ 
    private: 
     int x; 

    public: 
     B(int x); 

     int getX() const; 

     int operator + (const A& A); 
}; 


A::A(int x) : x(x) {} 

int A::getX() const { return x; } 

// Method 1 
int A::operator + (const B& b) { return getX() + b.getX(); } 


B::B(int x) : x(x) {} 

int B::getX() const { return x; } 

// Method 1 
int B::operator + (const A& a) { return getX() + a.getX(); } 


// Method 2 
int operator + (const A& a, const B& b) { return a.getX() + b.getX(); } 

int operator + (const B& b, const A& a) { return a.getX() + b.getX(); } 


#include <iostream> 

using namespace std; 

int main() 
{ 
    A a(2); 
    B b(2); 

    cout << a + b << endl; 

    return 0; 
}; 

私は上記のコードでは最良の方法である方法、二つのタイプの中で対称性を持っているしたい場合:ここで私は私の懸念を説明するために作った例があります。ある方法を他の方法よりも選択する可能性はありますか?これは返品の種類によって異なりますか?説明してください!ありがとうございました!

+0

AとBをよりよく説明し、それらがどのように関連しているかは、クリーンでシンプルな解決方法を決定するのに役立ちます。彼らは関連していますか? 1つのコンバーチブルはもう1つのコンバーチブルですか? –

答えて

8

最も良い方法は、(いずれかのクラスの外で)int operator+ (const A& a, const B& b)を定義し、必要に応じて両方のクラスのフレンド機能にすることです。さらに、定義する

int operator+(const B& b, const A& a) {return a + b;} 

対称にするには。

+0

する必要がある場合にのみ、それを友人にしてください。時にはあなたは時々あなたがして、時々あなたはしません。 –

+0

良い点。編集された – rlbond

+0

AとBの間で暗黙的に変換することはできません(例えば、明示されていないコンストラクタ)... – Uri

3

このアプローチの大きなリスクは、人々が対称演算子として知覚する傾向があることです。これが書かれている方法では、(あなたの実装が同じでない限り)そうではありません。

少なくとも、外部バイナリ演算子(メンバーではない)として+をオーバーロードしてから、数回オーバーロードして再生する必要があります。

何もあいまいにならないように注意する必要があります。

あなたは何をしようとしているのか説明できますか?私は、異種異種オペレータを持つことが理にかなっている、異なるタイプの多くのケースについて考えることはできません。

1

メソッド2の主な引数は、2番目のオペランドだけでなく、両方のオペランドに暗黙の型変換を行うことです。これにより、混乱をどこかで軽減できます。

あなたのサンプルコードでは、両方のクラスの1引数のコンストラクタを使用して、intからAおよびintからBへの暗黙的な変換を定義しています。後であいまいさにつながる可能性があります。しかし、あなたが簡潔さのために「明示的」を省いていれば、十分に公正である。

私はUriの警告に同意します:あなたがこれをやっていると分かっている人は、他の人が混乱するかもしれないAPIを書いているかもしれません。どのようにAプラスBがintですか? getXを自分で呼び出して結果を追加するのではなく、aとbを追加していることを実際にユーザーが簡単にしていますか?

ユーザーはAとBがintのラッパーであることを完全に知っているからですか?その場合、別のオプションは、演算子int()を使用して、AからintおよびBからintへの変換を公開することです。そして、+ bが賢明な理由のためにint型を返します、そして、あなたはあまりにも他のすべての算術演算子を取得します:私はあなたの意図された使用は、ベクトルや行列を追加してコメントに読ん

#include <iostream> 

struct A { 
    int x; 
    explicit A(int _x) : x(_x) {} 
    operator int() { 
     return x; 
    } 
}; 

struct B { 
    int x; 
    explicit B(int _x) : x(_x) {} 
    operator int() { 
     return x; 
    } 
}; 

int main() { 
    A a(2); 
    B b(2); 
    std::cout << a + b << "\n"; 
    std::cout << a - b << "\n"; 
} 
+0

例としてクラスAとBを作成しました。より実用的な例としては、乗算が両方の方法で定義されるMatrixクラスとVectorクラスがあります。 1つの方法は通常のベクトルを与え、もう1つは転置されたベクトルを返すことと同様に仮定する。 –

+0

その後、私の最初の段落の後のすべてを無視してください:-) –

+0

メンバー以外の演算子を両方のクラスの友達にする議論は何ですか?これはちょっと便利なのですか?「ゲッター」メソッドを書く必要がないか、あるいはいくつかの文法的な議論があるからですか? –

1

。たぶん、ベクトルが1次元の行列である行列だけを使うことを検討してください。あなたはベクトルクラスを維持したいならば、あなたはまた、転置ベクトル(多分転置ベクトルのちょうど内部プロパティであるかどうかを検討すべきである

matrix operator*(matrix const& a, matrix const& b); 
matrix operator+(matrix const& a, matrix const& b); // and so on 

:次に、あなたはただ一種類と演算子の1セットで残っています)。(転置と仮定すると、ベクトルの性質である)

vector * matrix = vector 
matrix * vector_t = vector_t 
matrix * matrix = matrix 
vector_t * vector = matrix 
vector * vector_t = int 

とは、あなたがこれらの3つの操作を提供する必要があります:

vector operator*(vector const& v, matrix const& m); 
vector operator*(matrix const& m, vector const& v); 
matrix operator*(matrix const& m1, matrix const& m2); 
matrix operator*(vector const& v1, vector const& v2); // possibly 1x1 matrix, you cannot overload changing only return value 

すべてとして

操作のセットは本当に対称ではありません可能であれば自由な機能を提供する。上記のセットが対称でない場合でも、現実の世界ではなく、ユーザーはそれを期待します。

関連する問題