你遇到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 *
調用時使函數完全消失。
整潔,小巧,獨立的例子。我希望每個有代碼問題的人都做了你所做的事情。 – Omnifarious 2010-08-19 02:22:56
不應該從Foo派生協變返回類型嗎? – Chubsdad 2010-08-19 02:58:25
嗨,大家好,感謝您的快速和有益的迴應。關於多態分配Steve的好建議。如果有人想知道爲什麼我要看這樣的結構,那麼在我的實際代碼中,'Goo'是一個由後續模板類繼承的模板類,'Foo'是訪問範圍類的'接口'。 – Tom 2010-08-19 04:31:05