2009-06-27 49 views
2

我爲數學對象編寫了一個抽象類,並定義了所有的運算符。而使用它,我碰到:定義一個適當的減法運算符

Fixed f1 = 5.0f - f3; 

我只有兩個減法運算符定義:

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.)

您是在「操作需要在左側的參數轉換」的陣營。如果你不想讓一個朋友,假設你有一個不明確的float構造函數Fixed,可以實現它:

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

然後實現minus作爲公共成員函數,大多數用戶不會因爲他們喜歡操作員而煩惱。

,如果你有operator-(float)我想,那麼你必須​​,所以如果你不具備的轉換操作符,你可以一起去:

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

或者只是Fixed(lhs) - rhs,如果你有一個明確的float構造函數。這些可能會或可能不如您的朋友實施效率。

不幸的是,語言是不會使出渾身解數,以容納那些誰發生厭惡的關鍵字之一,因此,運營商不能是靜態成員函數,並得到友好的效果這樣;-p

1
  1. 「那朋友是什麼......」
  2. 你可以(與構造接受float如)float和你的類型之間添加的隱式轉換...但我不使用friend認爲更好。
+1

2會不會真的做的工作 - 它可以讓你做到「固定(0.5F) - F3」,但隱式轉換不會發生在作爲成員函數實現的運算符的lhs中。實際上,「這個」始終是來電者提供的,而不是一些暫時的。 – 2009-06-27 09:49:50

0

當你定義這樣的事情時,你說我想讓這個操作符(你在類內)在特定類型上操作,例如在這裏漂浮。

鑑於朋友二元運算符,意味着兩種類型之間的操作。

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

通常,用於算術運算的自由函數運算符比實現成員函數要好。主要原因是你現在面臨的問題。編譯器會以不同的方式處理左側和右側。請注意,雖然嚴格的OO追隨者將只考慮類內部的那些方法大括號界面的一部分,但專家認爲它是argued,在C++中並非如此。

如果免費功能操作員需要訪問私人會員,請讓操作員成爲朋友。畢竟,如果它是在同一個頭文件中提供的(遵循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 - Fixed。減去,Fixed - doubledouble - Fixed。編譯器將找到自由函數,並將隱式轉換(例如通過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); 
}