2009-08-11 53 views
14

假設我有這些抽象類FooBar有沒有辦法轉發聲明協方差?

class Foo; 
class Bar; 

class Foo 
{ 
public: 
    virtual Bar* bar() = 0; 
}; 

class Bar 
{ 
public: 
    virtual Foo* foo() = 0; 
}; 

進一步假設我有派生類ConcreteFooConcreteBar。我想協變細化的foo()bar()方法,像這樣的返回類型:

class ConcreteFoo : public Foo 
{ 
public: 
    ConcreteBar* bar(); 
}; 

class ConcreteBar : public Bar 
{ 
public: 
    ConcreteFoo* foo(); 
}; 

因爲我們敬愛的單次編譯器這不會編譯不知道ConcreteBar將從Bar繼承,並讓ConcreteBar是一個完全合法的協變返回類型。簡單的向前聲明ConcreteBar也不起作用,因爲它沒有告訴編譯器有關繼承的任何信息。

這是C++的一個缺點我必須忍受這種困境嗎?

+0

我們很多人都認爲協方差不必要的 - 看到這個問題http://stackoverflow.com/questions/1260757/when-is-c-covariance-the-best-solution這是據我有關人員未能激起令人信服的答覆。 – 2009-08-18 12:24:32

+1

我正在使用大量現有代碼的kloc進行項目。簡單地通過協變地改變一些方法的返回類型,我能夠擺脫許多static_casts。如果我對上述問題有一個引人注目的解決方案,我可以擺脫更多。 – Tobias 2009-08-19 14:46:03

回答

4

你可以很容易地僞造它,但是你失去了靜態類型檢查。如果更換dynamic_casts通過​​,你有什麼編譯器內部使用,但你有沒有動,也沒有靜態類型檢查:

class Foo; 
class Bar; 

class Foo 
{ 
public: 
    Bar* bar(); 
protected: 
    virtual Bar* doBar(); 
}; 

class Bar; 
{ 
public: 
    Foo* foo(); 
public: 
    virtual Foo* doFoo(); 
}; 

inline Bar* Foo::bar() { return doBar(); } 
inline Foo* Bar::foo() { return doFoo(); } 

class ConcreteFoo; 
class ConcreteBar; 
class ConcreteFoo : public Foo 
{ 
public: 
    ConcreteBar* bar(); 
protected: 
    Bar* doBar(); 
}; 

class ConcreteBar : public Bar 
{ 
public: 
    ConcreteFoo* foo(); 
public: 
    Foo* doFoo(); 
}; 

inline ConcreteBar* ConcreteFoo::bar() { return &dynamic_cast<ConcreteBar&>(*doBar()); } 
inline ConcreteFoo* ConcreteBar::foo() { return &dynamic_cast<ConcreteFoo&>(*doFoo()); } 
+0

+1代碼努力;) – neuro 2009-08-11 09:53:50

+0

此解決方案的工作原理,但肯定不會贏得選美比賽:) – Tobias 2009-08-11 10:41:21

+0

如果參與者僅限於那些解決陳述問題的人,我不太確定結果:-)您顯然可以使用爲該類之一提供的語言提供的協方差,但我更願意保持對稱性。 – AProgrammer 2009-08-11 11:01:16

2

協方差是基於繼承圖上,這樣以來你不能聲明

class ConcreteBar : public Bar; 

因此無法告訴編譯器關於協方差。

但是你可以用模板的幫助下做到這一點,聲明ConcretFoo ::酒吧爲模板,後來邊界允許你解決這個問題

+0

我知道你不能轉發聲明繼承。而模板也無濟於事,因爲模板成員函數不能是虛擬的。 – Tobias 2009-08-11 10:45:42

+0

不完全:在這裏我的示例工作!

 class ConcreteFoo : public Foo { public: template  T* bar(); }; template <> ConcreteBar* ConcreteFoo::bar(){} 
Dewfy 2009-08-11 11:15:51

+0

您是否嘗試過調用您的方法? – Tobias 2009-08-18 12:13:06

3

不靜態多態性解決問題了嗎? 通過模板參數爲派生類提供基類? 那麼基類將知道派生類型並聲明一個合適的虛擬?

1

這個怎麼樣。

template <class BarType> 
class Foo 
{ 
public: 
    virtual BarType* bar() = 0; 
}; 

template <class FooType> 
class Bar 
{ 
public: 
    virtual FooType* foo() = 0; 
}; 

class ConcreteBar; 
class ConcreteFoo : public Foo<ConcreteBar> 
{ 
public: 
    ConcreteBar* bar(); 
}; 

class ConcreteBar : public Bar<ConcreteFoo> 
{ 
public: 
    ConcreteFoo* foo(); 
}; 
相關問題