派生类重写函数修改返回值常量性为何未触发编译错误?
问题
基类中声明了返回const Widget&的纯虚函数,但派生类DerivedAgain重写该函数时,将返回类型改为Widget&(去掉了const修饰),且使用override关键字,代码却能正常编译通过。这是否符合C++标准,还是编译器存在错误?
复现代码如下:
struct Widget { int x = 42; }; struct Base { virtual const Widget & GetWidget() = 0; }; struct Derived : public Base { virtual const Widget & GetWidget() override { return m_widget; } private: Widget m_widget; }; struct DerivedAgain : public Derived { virtual /* missing "const"*/ Widget & GetWidget() override // Shouldn't compile? { return m_widgetAgain; } private: Widget m_widgetAgain; }; void main() { DerivedAgain thing; thing.GetWidget().x = 666; // Shouldn't be allowed? }
操作:编译上述源文件
预期结果:触发编译错误
实际结果:编译成功
Build started at 11:33 AM... 1>------ Build started: Project: Test, Configuration: Debug Win32 ------ 1>Test.cpp ========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ========== ========== Build completed at 11:33 AM and took 00.301 seconds ==========
解答
这完全符合C标准的规定,并非编译器错误。核心原因是**C允许虚函数重写时使用协变返回类型**,具体到引用类型的规则是:如果基类虚函数返回const T&,派生类重写时可以返回T&——因为T&可以安全地隐式转换为const T&,满足协变返回类型的要求。
当通过基类指针或引用调用GetWidget时,得到的是const Widget&,无法修改成员;但直接通过DerivedAgain对象调用时,调用的是派生类的版本,返回的是Widget&,自然允许修改x的值,这是合法的。
override关键字在这里能正常通过,因为编译器认可这种返回类型的协变关系,判定该函数确实是对基类虚函数的重写。
内容的提问来源于stack exchange,提问作者GeoRanger
相关产品推荐
相关产品推荐

