我知道没有办法强制 C++ 编译器禁用动态绑定,除非它支持这样的选项(并非所有 C++ 编译器都这样做,但大多数编译器都这样做)。但是,这有点像把婴儿和洗澡水一起扔了,因为它在理论上禁用了所有不属于 C 的 C++ 功能。
当然,在 C++11 中引入了 final 标识符,它可以防止从类中进一步派生或覆盖虚拟成员。严格来说,这并不能阻止动态调度 - 它解决了一个不同的问题。
避免动态绑定的影响(感知或实际)的一种方法是避免使用或编写任何具有虚成员函数的类,并且不创建类层次结构(即不要从具有虚函数的类派生)。显然,如果没有虚函数在起作用,就不需要虚函数调度,因此不需要动态绑定。
如果您知道对象的类型,则可以通过使用静态调度来避免使用动态绑定,即显式命名要调用的函数。例如,假设我们有一个类Base,它提供一个名为foo() 的publicvirtual 成员和一个名为Derived 的类,它继承自Base 并覆盖foo()。那么下面就避免做动态调度了;
Base *b = new Derived;
b->Base::foo(); // static call; will not call `Derived::foo()`
b->Derived::Foo(); // incorrect static call. Will not compile since b is a pointer to Base not Derived
Derived *d = new Derived;
d->Derived::foo(); // static call of Derived::foo()
d->Base::foo(); // static call of Base::foo()
当然,如果使用对象的代码依赖于对象的 ACTUAL 类型的知识,或者依赖于被调用的 foo() 的特定变体,那么它的设计有点违背了拥有多态基础的目的类和其他派生自它的类。
在上面,编译器仍将支持虚函数调用(vtable 等,如果现在编译器可以工作的话),这可能会影响创建和销毁对象的过程。
另一种避免动态分派(或绑定)的技术是使用模板(有时称为编译时多态性)。本质上,模板可能假设一个类型提供了一些接口(或一组操作),并且可以使用该接口的任何类型的变量。例如;
struct X
{
void foo();
};
template<class T> void func()
{
T x; // relies on T being instantiable (and destructible)
x.foo(); // relies on T having a member named foo()
}
// in some function somewhere where both X and func() are known to the compiler
func<X>();
此类模板不需要T 类型具有虚函数,因此不要依赖动态调度(绑定)。但是,没有什么可以阻止这样的模板函数与具有虚拟成员函数的类一起使用,因此这不会禁用动态绑定 - 它只允许程序员做出选择以避免使用动态绑定。
如果我在面试中被问到这个问题,我可能会指出以上所有内容,但不要说这个问题相当愚蠢。熟悉 C++ 的面试官会意识到这一点,并且只会对你如何思考和解决这样的问题感兴趣(毕竟现实世界的开发人员经常被管理层或客户要求满足愚蠢或不切实际的要求,并且期望是机智的足以避免告诉他们的经理或客户他们很愚蠢)。如果面试官在不理解的情况下提出了这个问题(或者在房间里没有其他理解这一点的面试小组成员),我无论如何都不想与那个雇主合作。