2012-10-21 43 views
4

我想寫一個抽象類與一些純粹的虛擬二元運算符,這應該由派生類實現以實現運算符多態性。這裏有一個簡單的例子:如何在抽象類中聲明重載運算符並在派生的非抽象類中重寫它?

class Base { 
public: 
    virtual const Base& operator+ (const Base&) const = 0; 
}; 

class Derived : public Base { 
public: 
    const Derived& operator+ (const Derived&) const; 
}; 

const Derived& Derived::operator+ (const Derived& rvalue) const { 
    return Derived(); 
} 

不要緊,現在運營商做什麼,重要的部分是它返回:返回一個臨時的派生對象,或者對它的引用。現在,如果我嘗試編譯,我得到這個:

test.cpp: In member function ‘virtual const Derived& Derived::operator+(const Derived&) const’: 
test.cpp:12:17: error: cannot allocate an object of abstract type ‘Derived’ 
test.cpp:6:7: note: because the following virtual functions are pure within ‘Derived’: 
test.cpp:3:22: note: virtual const Base& Base::operator+(const Base&) const 

怎麼了?是不是operator +(Base中唯一的純虛函數)被覆蓋? Derived爲什麼也應該是抽象的?

+0

看起來它是因爲函數有不同的簽名的原則。 const const Derived&Derived :: operator +(const Derived&rvalue)const' vs'virtual const Base&Derived :: operator +(const Base&)const' –

+0

順便說一句,您不能返回對臨時對象的引用,因爲referand的生存期是隻要函數返回就結束。 'operator +'需要按值返回,當調用者期望一個'Base'時,這會排除返回'Derived'。 –

回答

1

這種超載是不可能在一個乾淨的方式正常的抽象類。首先:你應該聲明+爲非會員Overload operators as member function or non-member (friend) function?

你能得到的最好的是從模板接口繼承,如果你真的需要這個功能:

template<typename T> 
class AddEnabled { 
    public: 
    friend T operator+ (T const& left, T const& right) { 
     return left+=right; 
    } 
}; 

現在你寫

class Foo: public AddEnabled<Foo>{ 
    Foo():mVal(0){ 
    } 

    Foo& operator+=(Foo const& foo){ 
    mVal+=foo.mVal; 
    } 

private: 
    int mVal; 
} 

如果您註釋掉Foo& operator+=(Foo const& foo){你會得到一個編譯器錯誤說運營商沒有實施。如果您想了解更多關於參與查找http://en.wikipedia.org/wiki/Barton%E2%80%93Nackman_trickhttp://en.wikipedia.org/wiki/Curiously_recurring_template_pattern

HTH,馬丁

+0

所以,如果你有多個派生類(例如'Foo'和'Bar'),那麼我想在這裏它們對於實現'AddEnabled '和'AddEnabled '都是有意義的。但是,如何處理Foo + Foo與Foo + Bar或Bar + Bar等實現不同的情況? –

+1

@PantelisSopasakis:這取決於。如果Foo和Bar沒有繼承關係,則可以簡單地將這些函數實現爲非成員(也可能是非友元函數)並完成它。如果你有他們之間的繼承,我肯定會避免通過運算符重載來做到這一點。您的代碼很快就會變得非常容易出錯 – Martin

6

雖然Derived中的返回類型可以與基本類型共同變體,但不能對參數類型做同樣的處理。即,最重要的功能應該是這樣的:

class Derived : public Base 
{ 
public: 
    const Derived& operator+ (const Base&) const; 
};