virtual
方法是多态性的 C++ 实现的一部分。除了避免与 RTTI **和方法查找相关的开销之外,是否有令人信服的理由省略virtual
?
假设virtual
可以随时将其添加到基类中,重新定义非virtual
方法的目的是什么?
**它是否可以在现代 CPU 上测量与这个问题无关。
virtual
方法是多态性的 C++ 实现的一部分。除了避免与 RTTI **和方法查找相关的开销之外,是否有令人信服的理由省略virtual
?
假设virtual
可以随时将其添加到基类中,重新定义非virtual
方法的目的是什么?
**它是否可以在现代 CPU 上测量与这个问题无关。
好吧,没有什么理由重新定义一个非虚函数。事实上,我建议不要这样做,因为看起来对完全相同的对象的相同函数调用可能会根据所使用的指针/引用的静态类型而表现不同。
覆盖虚拟成员函数允许您专门化派生类型的行为。重载非虚拟成员函数将提供另一种行为,在这种行为中,对于不经意的读者来说,将执行哪些函数/行为可能并不明显。
一种可能的用途是实现一个定义了默认函数版本的 CRTP 框架:
#include <iostream>
//This could be any higher-order function.
template<typename T>
class CallFiveTimes {
protected:
void docalls() const {
for(int i(0); i != 5; ++i) static_cast<T const*>(this)->callme();
}
//Default implementation. If a lot
//of different functionality were required of `T`
//then defaults could make `T` easier to write.
void callme() const {
std::cout << "Default implementation.\n";
}
};
class Client : CallFiveTimes<Client> {
public:
void useFramework() {
docalls();
}
private:
friend struct CallFiveTimes<Client>;
//This redefinition will be used.
void callme() const {
std::cout << "Client implementation.\n";
}
};
class LazyClient : CallFiveTimes<LazyClient> {
public:
void useFramework() {
docalls();
}
friend struct CallFiveTimes<LazyClient>;
};
int main() {
Client c;
c.useFramework(); //prints "Client Implementation" five times
LazyClient lc;
lc.useFramework(); //prints "Default Implementation" five times
}
我在实践中从未见过这样做,但在某些情况下可能值得考虑。