面试题答案
一键面试运行时多态性问题
- 行为不符合预期:由于非虚函数在编译时就确定了调用版本,当通过基类指针或引用调用该函数时,无论实际指向的是基类对象还是派生类对象,调用的都是基类的函数版本,而不是派生类重新定义的版本。这与运行时多态性的概念相悖,运行时多态性期望根据对象的实际类型来决定调用哪个函数版本。例如:
class Base {
public:
void nonVirtualFunction() {
std::cout << "Base::nonVirtualFunction" << std::endl;
}
};
class Derived : public Base {
public:
void nonVirtualFunction() {
std::cout << "Derived::nonVirtualFunction" << std::endl;
}
};
int main() {
Base* basePtr = new Derived();
basePtr->nonVirtualFunction(); // 输出 "Base::nonVirtualFunction",而非 "Derived::nonVirtualFunction"
delete basePtr;
return 0;
}
- 隐藏了基类函数:派生类重新定义非虚函数,会隐藏基类中的同名函数。这意味着如果在派生类对象上调用该函数,只能调用到派生类版本,即使通过作用域解析运算符
::
也不能直接调用基类版本(除非在派生类中显式地声明using Base::nonVirtualFunction;
)。
代码可维护性问题
-
增加维护成本:代码的维护者可能期望通过基类指针或引用调用函数时,会遵循运行时多态性的规则,调用到实际对象类型对应的函数版本。但由于非虚函数的存在,这种期望会落空,导致调试和理解代码的难度增加。当需要修改函数行为时,可能需要在多个地方进行修改,不仅要修改派生类中的函数,还要考虑通过基类指针或引用调用时的情况。
-
破坏代码的一致性:在类继承体系中,通常约定虚函数用于实现运行时多态性,非虚函数用于提供一些通用的、不应该被派生类改变的行为。派生类重新定义非虚函数打破了这种约定,使得代码结构变得混乱,降低了代码的可读性和可维护性。
-
影响代码复用:如果其他代码依赖于基类的非虚函数行为,派生类重新定义该函数可能会导致这些代码在使用派生类对象时出现意外行为,从而影响整个代码库的复用性。