2009-06-27 9 views
2

私は、数学オブジェクトの抽象クラスを作成し、すべての演算子を定義しました。それを使用している間、私が出会った:適切な減算演算子を定義する

Fixed f1 = 5.0f - f3; 

私は定義された2つだけ減算の演算子があります。

inline const Fixed operator -() const; 
inline const Fixed operator - (float f) const; 

を私がここに間違っているものを手に入れる - ほかには、(1 + 2 == 2 + 1)スワップに対応しています減算はしません(乗算と除算で同じです)。 私はすぐにこのよう外の私のクラスの機能を書いた:

static inline const Fixed operator - (float f, const Fixed &fp); 

しかし、その後、私はキーワードfriendを使用して、その結果、私はクラスの陰部に触れなければならないことをやっているので、これは、実行することはできません実現名前空間を「静的な」不要な関数で汚染するだけでなく、私は嫌われます。

のgcc-4.3のクラス定義の利回りの内側に、このエラーを機能の移動:

error: ‘static const Fixed Fixed::operator-(float, const Fixed&)’ must be either a non-static member function or a non-member function 

GCCが示唆されているように行う、非静的な関数は次のエラーを生じ、それを作る:

error: ‘const Fixed Fixed::operator-(float, const Fixed&)’ must take either zero or one argument 

なぜクラス定義内で同じ演算子を定義できないのですか?それを行う方法がない場合は、とにかくfriendキーワードを使用していないのですか?

同じ問題を抱えているので、同じ質問が分裂する。

答えて

3

あなたはその友人を安心させたい場合の機能はOKになります

http://www.gotw.ca/gotw/084.htm

Which operations need access to internal data we would otherwise have to grant via friendship? These should normally be members. (There are some rare exceptions such as operations needing conversions on their left-hand arguments and some like operator<<() whose signatures don't allow the *this reference to be their first parameters; even these can normally be nonfriends implemented in terms of (possibly virtual) members, but sometimes doing that is merely an exercise in contortionism and they're best and naturally expressed as friends.)

あなたがキャンプ「左側の引数に変換を必要とする操作」です。その後、ほとんどのユーザーがないことを、パブリックメンバ関数としてminusを実装

static inline Fixed operator-(const Fixed &lhs, const Fixed &rhs) { 
    return lhs.minus(rhs); 
} 

:あなたが友人をしたい、とあなたはFixedための非明示的なfloatコンストラクタを持って想定していない場合は、としてそれを実装することができます彼らはオペレーターを好むので気にする。

私はあなたがoperator-(float)を持っているならば、あなたは​​を持っているので、あなたは変換演算子を持っていない場合、あなたが行くことができると仮定します。あなたは明示的なfloatコンストラクタを持っている場合

static inline Fixed operator-(float lhs, const Fixed &rhs) { 
    return (-rhs) + lhs; 
    // return (-rhs) -(-lhs); if no operator+... 
} 

それともFixed(lhs) - rhs。それらは、あなたの友人の実装ほど効率的でないかもしれません。

残念ながら、言語は

1
  1. あなたは(floatを受け入れるコンストラクタで例えば)floatとあなたのタイプの間の暗黙的な変換を追加することができます...しかし、私はfriend使っ思います「それは友人が何であるかのため...です」優れている。
+1

2のいずれかの周りに最も驚くべきコードではありませんので、実際に仕事をしていないだろう - それはあなたが行うようになる「(0.5F)を修正 - F3」が、暗黙の変換は、メンバー関数として実装された演算子のlhsには決して起こりません。実際には、「これ」は常に発信者が提供するものであり、一時的なものではありません。 –

+0

lhsをその演算子を持つ型に変換することができれば、名前解決の全く新しい次元を持ち、標準化委員会の趣味にあまりにも多くのあいまいさが生じる理由は分かりません。 –

0

;-pそのように、オペレータは、静的メンバ関数にはできませんので、そのキーワードのいずれかを嫌うために起こる人たちに対応するために後方に曲げると友情の効果を取得するつもりはありませんあなたはこのような何かを定義し、

inline const Fixed operator - (float f) const; 

あなたは、例えばここに浮かぶ、特定のタイプに動作させるために(あなたがクラス内にある)私はこの作業をしたいと言っています。

フレンドバイナリ演算子は、2つのタイプ間の演算を意味します。

class Fixed 
{ 
    inline friend const Fixed operator-(const Fixed& first, const float& second); 
}; 

inline const Fixed operator-(const Fixed& first, const float& second) 
{ 
    // Your definition here. 
} 

フレンドオペレーターがオペレーターのどちらかの側に自分のクラスを持つことができます。

0

一般に、算術演算のためのフリー関数演算子は、メンバ関数を実装するよりも優れています。主な理由はあなたが今直面している問題です。コンパイラは左右の辺を別々に扱います。厳密なオブジェクト指向の信者は、クラス内のメソッドだけがそのインタフェースの中括弧を考慮していると考えていますが、専門家はC++のケースではないとarguedです。

自由機能の演算子でプライベートメンバーにアクセスする必要がある場合は、演算子フレンドを作成します。結局のところ、同じヘッダファイル(上記のSutterの理論的根拠に従う)に提供されていれば、それはクラスの一部です。

本当にそれを避け、あなたのコードをあまり慣れないように(そして管理しにくいように)したいのであれば、実際の作業を行い、そのメソッドにオペレータからディスパッチするパブリックメソッドを提供できます。上記のコードで

class Fixed { 
private: 
    Fixed(); 
    Fixed(double d); // implicit conversion to Fixed from double 

    Fixed substract(Fixed const & rhs) const; 
// ... 
}; 

Fixed operator-(Fixed const & lhs, Fixed const & rhs) 
{ 
    return lhs.substract(rhs); 
} 

、あなたはFixed - FixedFixed - doubledouble - Fixedをsubstractすることができます。コンパイラは空き関数を見つけて、doubleコンストラクタを通して暗黙的にdoubleをFixedオブジェクトに変換します。

これは算術演算子では一義的ですが、多型ダンプ演算子を証明する慣習的な方法には近いです。最も自然な解決策ではないが、それは

// idiomatic polymorphic dump operator 
class Base { 
public: 
    virtual std::ostream& dump(std::ostream &) const; 
}; 
std::ostream& operator<<(std::ostream& o, Base const & d) 
{ 
    return d.dump(o); 
} 
関連する問題