首先让我说明我理解虚方法的工作原理(多态,后期绑定,vtables).
我的问题是我是否应该将我的方法设为虚拟.我将举例说明我在特定情况下的困境,但任何一般指导方针也会受到欢迎.
上下文:
我正在创建一个库.在这个库中,我有一个CallStack类,它捕获一个调用堆栈,然后提供对捕获的堆栈帧的类似矢量的访问.捕获由受保护的CaptureStack方法完成.如果库的用户希望实现另一种捕获堆栈的方法,则可以在派生类中重新定义此方法.为了清楚起见,使方法虚拟的讨论仅适用于我知道可以在派生类(在本例中为CaptureStack和析构函数)中重新定义的某些方法,而不是所有类方法.
在我的库中,我使用CallStack对象,但从未作为指针或引用参数公开,因此只考虑使用我的库而不需要虚拟.
当有人想要使用CallStack作为实现多态性的指针或引用时,我无法想到这种情况.如果有人想要派生CallStack并重新定义CaptureStack,我认为只使用派生类对象就足够了.
现在只是因为我不能认为需要多态,我不应该使用虚方法,或者我应该使用虚拟,因为一个方法可以重新定义.
示例如何在我的库外使用CallStack:
if (error) {
CallStack call_stack; // the constructor calls CaptureStack
for (const auto &stack_frame : call_stack) {
cout << stack_frame << endl;
}
}
重新定义CaptureStack的派生类可以以相同的方式使用,不需要多态:
if (error) {
// since this is not a CallStack pointer / reference, virtual would not be needed.
DerivedCallStack d_call_stack;
for (const auto &stack_frame : d_call_stack) {
cout << stack_frame << endl;
}
}
解决方法:
在决定是否需要虚函数时,您需要查看派生和覆盖函数是否会更改您现在正在实现的其他函数的预期行为/功能.
如果您依赖于同一个类的其他进程中该特定函数的实现,就像同一个类的另一个函数一样,那么您可能希望将该函数作为虚函数.但是如果你知道你的父类应该做什么功能,并且你不希望任何人在你担心的情况下改变它,那么它就不是虚函数.
或者作为另一个例子,假设某人从您的实现派生一个类,覆盖一个函数,并将该对象作为一个父类传递给您自己实现的函数/类之一.您是否希望拥有该函数的原始实现,或者您希望它们使用自己的覆盖实现?如果是后者,那么你应该去虚拟,除非没有.