2010-08-19 54 views
8

改寫純虛函數只是一個小煩惱真的,我可以通過包裝導出的功能,而不是使用「使用」關鍵字解決這個問題,但爲什麼不下面的工作(在編譯器告訴我'get_elem'在'Bar'類中仍然是純虛擬的)。通過「使用」單獨繼承方法

class Elem {}; 

class DerivedElem : public Elem {}; 

class Foo { 

    public: 
    virtual Elem& get_elem() = 0; 

}; 

class Goo { 

    protected: 
    DerivedElem elem; 

    public: 
    DerivedElem& get_elem() { return elem; } 

}; 


class Bar : public Foo, public Goo { 

    public: 
    using Goo::get_elem; 

}; 

int main(void) { 

    Bar bar; 

} 

乾杯,

湯姆

+4

整潔,小巧,獨立的例子。我希望每個有代碼問題的人都做了你所做的事情。 – Omnifarious 2010-08-19 02:22:56

+0

不應該從Foo派生協變返回類型嗎? – Chubsdad 2010-08-19 02:58:25

+0

嗨,大家好,感謝您的快速和有益的迴應。關於多態分配Steve的好建議。如果有人想知道爲什麼我要看這樣的結構,那麼在我的實際代碼中,'Goo'是一個由後續模板類繼承的模板類,'Foo'是訪問範圍類的'接口'。 – Tom 2010-08-19 04:31:05

回答

2

在您的例子中,Foo和粘粘是分開的類。在Bar中,來自Goo的get_elem方法與Foo中的方法完全不同,即使它們的簽名匹配。

通過擁有using Goo::get_elem,您只需告訴編譯器解析對Goo中get_elem()的非限定調用。

1

你遇到C++的許多偏僻的角落裏的一個。在這種情況下,C++並不認爲從不同類繼承的兩個虛函數是相同的函數,即使它們具有相同的名稱和類型簽名。

有一些很好的理由,C++,以這樣的行爲。例如,儘管事實上它們具有相同的名稱和類型簽名,但這兩個函數實際上並不相同。這兩個函數的語義含義是不同的。

下面是一個例子:

namespace vendor1 { 

class Circle { 
public: 
    virtual ::std::size_t size() const { return sizeof(*this); } 
}; 

} // namespace vendor1 


namespace vendor2 { 

class Shape { 
public: 
    virtual double size() const = 0; 
}; 

class Circle : public Shape { 
public: 
    virtual double size() const { return radius_ * radius_ * M_PI; } 
}; 

} // namespace vendor2 

然後你試試這個:

namespace my_namespace { 

class Circle : public ::vendor1::Circle, public ::vendor2::Circle { 
// Oops, there is no good definition for size 
}; 

所以你不得不求助於此:

namespace my_namespace { 

class Vendor1Circle : public ::vendor1::Circle { 
public: 
    virtual ::std::size_t data_structure_size() const { return size(); } 
}; 

class Vendor2Circle : public ::vendor2::Circle { 
public: 
    virtual double area() const { return size(); } 
}; 

class Circle : public Vendor1Circle, public Vendor2Circle { 
// Now size is still ambiguous and should stay that way 
// And in my opinion the compiler should issue a warning if you try 
// to redefine it 
}; 

所以,C++有充分的理由使用相同的類型簽名來處理虛擬函數(返回類型不是類型簽名的一部分),並從兩個不同的名稱中獲得名稱nt基地作爲不同的功能。

只要using去...所有using指令說是「從這個其他名稱空間添加名稱到這個名稱空間,就好像這裏有聲明。」。就虛擬功能而言,這是一個空的概念。它只是表明,使用名稱時的任何含糊不清應該以不同的方式解決。它只聲明一個名稱,它沒有定義名稱。爲了重寫虛擬函數,需要新的定義。

OTOH,如果你把一個簡單的thunk重新定義的內聯這樣的:

class Bar : public Foo, public Goo { 

    public: 
    virtual DerivedElem& get_elem() { return Goo::get_elem(); } 
}; 

一個好的編譯器應該看到,知道,甚至不打擾創造功能,而不只是編造虛表項做正確的事情。它可能需要實際發出代碼並在符號被採用的情況下使用符號,但它應該仍然可以簡單地將虛擬表格調整爲在通過Foo *調用時使函數完全消失。