C++ 與 C++/CLI:虛函式參數的常量限定
$$ All of the following was tested using Visual Studio 2008 SP1 $$ 在 C++ 中,參數類型的 const 限定不影響函式的類型(8.3.5/3:“刪除任何修改參數類型的 cv-qualifier”)
因此,例如,在以下類層次結構中,
Derived::Foo覆蓋Base::Foo:struct Base { virtual void Foo(const int i) { } }; struct Derived : Base { virtual void Foo(int i) { } };考慮 C++/CLI 中的類似層次結構:
ref class Base abstract { public: virtual void Foo(const int) = 0; }; ref class Derived : public Base { public: virtual void Foo(int i) override { } };如果我然後創建一個實例
Derived:int main(array<System::String ^> ^args) { Derived^ d = gcnew Derived; }它編譯時沒有錯誤或警告。當我執行它時,它會引發以下異常,然後終止:
ClrVirtualTest.exe 中出現“System.TypeLoadException”類型的未處理異常
附加資訊:“Derived”類型中的方法“Foo”…沒有實現。
該異常似乎表明參數的 const 限定確實會影響 C++/CLI 中函式的類型(或者,至少它會以某種方式影響覆蓋)。但是,如果我註釋掉包含定義的行
Derived::Foo,編譯器會報告以下錯誤(在main實例化的行上Derived):錯誤 C2259:“派生”:無法實例化抽像類
如果我將 const 限定符添加到參數 of
Derived::Foo或從參數中刪除 const 限定符Base::Foo,它將編譯並執行而沒有錯誤。我認為如果參數的 const 限定影響函式的類型,如果派生類虛函式中參數的 const 限定與基類 virtual 中參數的 const 限定不匹配,我應該得到這個錯誤功能。
如果我將
Derived::Foo’s 參數的類型從 anint更改為 adouble,我會收到以下警告(除了上述錯誤,C2259):警告 C4490:“覆蓋”:錯誤使用覆蓋說明符;‘Derived::Foo’ 與基 ref 類方法不匹配
所以,我的問題是,函式參數的 const 限定是否會影響 C++/CLI 中函式的類型?如果是這樣,為什麼會編譯,為什麼沒有錯誤或警告?如果不是,為什麼會拋出異常?
嗯,這是一個錯誤。const 修飾符通過 modopt 自定義修飾符發送到元數據中。不幸的是,C++/CLI 語言規則與 CLI 規則不匹配。CLI 規範的第 7.1.1 章說:
使用 modreq(“必需的修飾符”)和 modopt(“可選的修飾符”)定義的自定義修飾符與自定義屬性(第 21 節)類似,只是修飾符是簽名的一部分,而不是附加到聲明中。每個修飾符將類型引用與簽名中的項目相關聯。
CLI 本身應以相同的方式處理必需的和可選的修飾符。僅通過添加自定義修飾符(必需或可選)而不同的兩個簽名不應被視為匹配。自定義修飾符對 VES 的操作沒有其他影響。
因此,CLR 說 Derived::Foo() 不是覆蓋,C++/CLI 說它是。CLR 獲勝。
您可以在 connect.microsoft.com 上報告該錯誤,但這可能是在浪費時間。我認為這種不兼容是故意的。他們應該更改 C++/CLI 的語言規則,但肯定認為 C++ 兼容性更重要。無論如何,CV 修飾符都是一種痛苦,還有其他一些場景沒有得到很好的支持,比如 const 指向 const 的指針。無論如何,這不能在執行時強制執行,CLR 不支持它。