[英]Does the function override the base function?
我有三個不同的編譯器,我用來編譯這段代碼。 其中一個(我最信任的那個)警告Derived中的函數隱藏了Base中的函數。 其他編譯器(一個是Visual C ++ )沒有警告。 如果我啟用/ Wall或/ W4,Visual C ++甚至不會發出警告。
我傾向於認為這是編譯器中的一個錯誤,它會發出警告,因為它編譯代碼。 如果它確實沒有覆蓋基函數,那么當我創建派生模板的實例時它應該給出錯誤。
任何人都可以確認這應該如何表現?
struct Base
{
virtual void Func(float f) = 0;
};
template <typename T>
struct Derived : Base
{
virtual void Func(T f){}
};
int main()
{
Derived<float> d;
d.Func(0);
return 0;
}
當使用float
實例化Derived
,我會收到意外警告。 當使用int
實例化Derived
,我會收到錯誤,如預期的那樣。
它確實被覆蓋了。 您可以使用override
關鍵字在C ++ 11中輕松說服自己,如果不覆蓋該函數,則不允許編譯代碼:
struct Base
{
virtual void Func(float f) = 0;
virtual ~Base() = default; // to silence warnings
};
template <typename T>
struct Derived : Base
{
void Func(T f) override {} // will fail to compile if not overriding
};
int main()
{
Derived<float> d;
d.Func(0);
return 0;
}
這里有實例。
請注意,在預C ++ 11中,您可以通過在派生類中更改其簽名來意外隱藏virtual
基本函數,因此即使您將派生函數標記為virtual
代碼仍然編譯,但不再具有多態性,請參閱此類這里的例子。 不幸的是,即使使用-Wall -Wextra
,g ++也不會提供任何警告。 這就是為什么override
是一種在編譯時實際執行真正覆蓋的更安全的方法。
我不相信你應該得到警告。
這與:
struct Derived : Base
{
virtual void Func(float f) { };
};
當您的模板參數為float
。
沒有隱藏,只有抽象函數的實現。
在此上下文中,隱藏函數的警告讓我們知道派生類中的成員函數具有相同的名稱,但簽名不同於基類中的函數。 考慮:
struct Base
{
void foo(int) {}
void bar(int) {}
};
struct Derived: Base
{
void bar(int, int) {}
};
int main()
{
Derived d;
d.foo(1);
d.bar(1); // will not compile: Base::bar is hidden by Derived::bar
}
在這個例子中,目的可能是添加一個名為“bar”的附加函數,但結果是一旦找到帶有名為bar的函數的作用域,編譯器就停止查找帶有函數名稱bar的新作用域。 因此bar(int)被bar(int,int)(或具有不匹配簽名的任何其他欄)隱藏。 (或者在非虛擬情況下,即使函數匹配。)
在這個Graznarak的代碼中,Base :: Func隱藏在Derived實例化為任何非浮點(或浮點const)的T值的情況下。
Graznarak詢問正確的行為。 生成的代碼的正確之前沒有問題Derived :: Func()被調用。
但這留下了一個問題:警告是否合適。 標准沒有答案。 它從不表達是否應該產生警告的意見。 是否警告特定問題總是主觀的,編制者可以通過在這方面表現出良好的判斷來區分自己。
那么你的編譯器應該警告這種情況嗎? 可以說,編寫的代碼可以完成預期的操作。 但是模板的存在意味着它將在多個類型上實例化(否則為什么要制作模板),對於任何其他類型,隱藏會發生。 因此,有人可能會爭辯說,應該在創建派生模板時給出警告。 但是人們也可以爭辯說,在指定非浮點類型實例化之前不應該發出警告。
爭論前者是警告會更早,並且可能由程序員編寫有問題的代碼來檢測。 爭論后者是在實例化非浮點類型之前,沒有可疑情況需要警告。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.