Jam*_*lis 10 .net virtual-functions c++-cli visual-c++
[以下所有内容均使用Visual Studio 2008 SP1进行了测试]
在C++中,参数类型的const限定不影响函数的类型(8.3.5/3:"删除修改参数类型的任何cv限定符")
因此,例如,在以下类层次结构中,Derived::Foo覆盖Base::Foo:
struct Base
{
virtual void Foo(const int i) { }
};
struct Derived : Base
{
virtual void Foo(int i) { }
};
Run Code Online (Sandbox Code Playgroud)
在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 { }
};
Run Code Online (Sandbox Code Playgroud)
如果我然后创建一个实例Derived:
int main(array<System::String ^> ^args)
{
Derived^ d = gcnew Derived;
}
Run Code Online (Sandbox Code Playgroud)
它编译没有错误或警告.当我运行它时,它会抛出以下异常然后终止:
ClrVirtualTest.exe中发生了未处理的"System.TypeLoadException"类型异常
附加信息:'Derived'类型中的方法'Foo'...没有实现.
该异常似乎表明参数的const限定确实会影响C++/CLI中函数的类型(或者,至少它会以某种方式影响覆盖).但是,如果我注释掉包含定义的行Derived::Foo,编译器将报告以下错误(在main实例Derived化实例的行上):
错误C2259:'Derived':无法实例化抽象类
如果我将const限定符添加到参数Derived::Foo或从参数中删除const限定符Base::Foo,它将编译并运行,没有错误.
我认为,如果该参数的常量资质影响函数的类型,我应该如果在派生类的虚函数的参数的常量资格并不在基类的虚拟匹配参数的常量资格得到这个错误功能.
如果我将Derived::Foo参数的类型从inta 更改为a double,我会收到以下警告(除了上述错误,C2259):
警告C4490:'覆盖':错误使用覆盖说明符; 'Derived :: Foo'与基本ref类方法不匹配
那么,我的问题是,有效的是,函数参数的const限制是否会影响C++/CLI中函数的类型?如果是这样,为什么这会编译,为什么没有错误或警告?如果没有,为什么会抛出异常?
嗯,这是一个错误.const修饰符使用modopt自定义修饰符发送到元数据中.遗憾的是,C++/CLI语言规则与CLI规则不匹配.CLI规范的第7.1.1节说:
使用modreq("required modifier")和modopt("可选修饰符")定义的自定义修饰符类似于自定义属性(§21),除了修饰符是签名的一部分而不是附加到声明.每个修饰符将类型引用与签名中的项相关联.
CLI本身应以相同的方式处理必需和可选的修饰符.仅通过添加自定义修饰符(必需或可选)而不同的两个签名不应视为匹配.自定义修改器对VES的操作没有其他影响.
因此,CLR说Derived :: Foo()不是覆盖,C++/CLI说它是.CLR获胜.
您可以在connect.microsoft.com上报告错误,但这可能是浪费时间.我认为这种不相容是故意的.他们应该更改C++/CLI的语言规则,但肯定认为C++兼容性更重要.无论如何,CV修饰符都是一种痛苦,还有其他不受支持的场景,const指针指向const.无论如何,这都无法在运行时强制执行,CLR不支持它.