2017-07-13 9 views
0

いくつかのコードのメンテナンスを行っていますが、は簡略化する必要があります。の方が、読みやすく、コードの数が少なくて済みます。 次のサンプルクラスを考える:オペレータでのオブジェクトポインタの比較===

class MyClass 
{ 

public: 
    MyClass(); 
    MyClass(Object1* o1, Object2* o2, Object3* o3, Object4* o4); 
    ~MyClass(); 

    MyClass &operator=(const MyClass &other); 
    void copy(const MyClass &other); 
    bool operator==(const MyClass &other) const; 

    ... 

private: 
    Object1* o1 = 0; 
    Object2* o2 = 0; 
    Object3* o3 = 0; 
    Object4* o4 = 0; 
}; 

このクラスは、1〜4の任意のオブジェクトで構成されています。

これらのオブジェクトがnullになる可能性がありますので、私は等しい演算子に来たときに、私が見つけた次等しい演算子が必要な場合、私は議論を持参する必要はありません

bool MyClass::operator==(const MyClass &other) const 
{ 
    if (o1 && (other.o1 == NULL)) return false; 
    if ((o1 == NULL) && other.o1) return false; 
    if (o1 && other.o1){ if (*o1!= *other.o1) return false; } 
    if (o2 && (other.o2 == NULL)) return false; 
    if ((o2 == NULL) && other.o2) return false; 
    if (o2 && other.o2){ if (*o2!= *other.o2) return false; } 
    if (o3 && (other.o3 == NULL)) return false; 
    if ((o3 == NULL) && other.o3) return false; 
    if (o3 && other.o3){ if (*o3!= *other.o3) return false; } 
    if (o4 && (other.o4 == NULL)) return false; 
    if ((o4 == NULL) && other.o4) return false; 
    if (o4 && other.o4){ if (*o4!= *other.o4) return false; } 
    return true; 
} 

かそうではない、私はちょうど上記のコードを簡素化する方法があるかどうかを知りたい。

一般的なこと:等価演算子でオブジェクトポインタを比較する最も標準的で効率的な方法は何ですか?

+0

誰かがなぜdownvotesを説明するために親切かもしれませんか? – ABCplus

+0

誰かがこれを意見/討論の質問と解釈している可能性があります。それはかなり近いです。 –

+0

Mmm ...質問はいくつかの特定のコードに関連しています – ABCplus

答えて

2

実際にコードを簡略化したい場合は、ポインタの使用をやめ、実際にはoptionalのオブジェクトを使用してください。次のいずれかを実行できwait for std::optional(C++ 17、これだけ数ヶ月と新しいコンパイラはおそらく既にそれをサポートしています)、またはブーストを使用します。

#include <boost/optional.hpp> 

class MyClass 
{ 

public: 
    MyClass(
     boost::optional<Object1> o1 = boost::none, 
     boost::optional<Object2> o2 = boost::none, 
     boost::optional<Object3> o3 = boost::none, 
     boost::optional<Object4> o4 = boost::none 
    ) : o1(o1), o2(o2), o3(o3), o4(o4) {} 

private: 
    boost::optional<Object1> o1; 
    boost::optional<Object2> o2; 
    boost::optional<Object3> o3; 
    boost::optional<Object4> o4; 
}; 

またはちょうどかなり簡単に独自のロール。

これらすべての演算子や独自のコピーコンストラクタは必要ありません。

いつものように、キーは特定のロジックを抽象化しているので、きれいに再利用できます。この場合、まだどこかにoperator==がありますが、まだコピーコンストラクタがどこかにありますが、optionalの内部に実装しており、それぞれのインスタンスに対してen masseを再作成する必要はありません。複数のインスタンスが自然に構成されます。

あなたが本当にあなたの現在の実装に固執したい場合は、少なくとも短縮することができます。

if (o1 && (other.o1 == NULL)) return false; 
if ((o1 == NULL) && other.o1) return false; 
if (o1 && other.o1){ if (*o1!= *other.o1) return false; } 

をする:

if (!o1 != !other.o1) return false; 
if (o1 && (*o1 != *other.o1)) return false; 

、それはまだ少しのEWのですが。

+0

しかし、ブーストやC++ 17がないと、オプションのクラスメンバーや関数のパラメータとしてポインタが良い選択になりますか? – ABCplus

+0

@ABCplus:結果としてコードの残りの部分に過度の合併症を漏らすことについての上記の注意点、はい。 –

+0

@LightnessRacesinOrbit 'o1'とother.o1'が等価なオブジェクトを分離するように指しているときに' if(o1!= other.o1)false false;が間違って返されます。 – Quentin

0

フィールドゲッターを受け入れるコンパレータの作成はどうですか?

template< typename TGetter > bool 
Eq(MyClass const & left, MyClass const & right, TGetter && getter) 
{ 
    auto const p_left(getter(left)); 
    auto const p_right(getter(right)); 
    return((!p_left && !p_right) || (p_left && p_right && (*p_left == *p_right))); 
} 

bool MyClass::operator==(const MyClass &other) const 
{ 
    return 
    (
     Eq(*this, other, [](const MyClass & inst){return inst.o1;}) 
     && 
     Eq(*this, other, [](const MyClass & inst){return inst.o2;}) 
     && 
     Eq(*this, other, [](const MyClass & inst){return inst.o3;}) 
     && 
     Eq(*this, other, [](const MyClass & inst){return inst.o4;}) 
    ); 
) 
+0

少なくとも読むのはずっと簡単です。しかし、 'getter'の結果が逆参照されるポインタであると仮定すると、' Eq'よりも良い名前が必要です。 –