当前位置: 首页 > 知识库问答 >
问题:

为什么派生类中的虚函数也是虚函数?

习宸
2023-03-14

为什么一个虚函数在派生类中默认是虚的,甚至不可能在派生类中完全移除虚性,这有什么好的理由吗?

我希望这种行为的原因与我不希望默认情况下每个函数都是virtual的原因相同。编译器可能会生成牺牲性能的vtables。

基类应该有一个vtable(我想要多态性在那里),但派生类没有vtable(我不希望多态性在那里,为什么我要那样,只是因为它派生了一个具有多态性的类?)。

我想解决的问题是更好地理解虚函数。我只是没有得到这个设计决定,想知道是否有任何原因。

共有3个答案

冀鸿才
2023-03-14

当一个方法被声明时,声明类根据该方法的性质来决定它是否是虚拟的。

当您重写这样的方法时,您的重写方法是执行完全相同操作的专用版本。您的重写方法无法决定它正在做一些无法专门化的事情,基类已经做出了决定。方法的性质由最初声明它的类(基类)决定。

Vtable是一个不应该影响这些的实现细节。

罗星洲
2023-03-14

我想你对vtable的功能感到困惑。从B派生的类C的vtable基本上将函数说明符映射到类C的函数指针。所以如果你这么做

B* ptr = new C;
ptr->foo();

我们必须查看运行时,调用哪个函数。最后,我们需要一个指向C::foo的函数指针,因为B不可能知道它在哪里,因为它根本不知道C。因此,这里我们需要C的vtable来进行调用。现在你可以争辩说我们这里不需要B的vtable。但是ptr也可以指向B类型的Object,所以你需要Bvtable。

可以说,可以做这样的事情(当然,伪代码):

virtual_call_to_foo(B* ptr) {
    if(ptr->is_actually_base_class) {
        ptr->B::foo(); // non-virtual call
    } else {
        ptr->vtable["foo"](); // indirect call
    }
}

但这并不比仅仅使用 B 的 vtable 更好,因为您已经在那里有了间接寻址。

此外,请注意,如果C::foo最终,则通过指针对C调用不会是虚拟的:

B* ptr = new C;
ptr->foo();  // virtual call
static_cast<C*>(ptr)->foo(); // non-virtual call, the compiler can inline this
柯翔
2023-03-14

特定类的vtable具有指向该特定类的虚函数的指针。基类的vtable不指向派生类覆盖的虚函数。可能有许多派生类,基类精确地知道它们中的零个,因此不可能有指向这些函数的指针。只有派生类的vtable可能有指向派生类函数的指针。

虚拟函数的要点是,如果将派生类的对象转换为基类指针/引用,则调用基类中声明的任何虚拟函数都必须为该对象调用该函数的最派生类版本。唯一的方法是如果该对象的vtable具有指向该函数的最派生类版本的指针。只有当该对象的vtable是派生类的vtable时,才会发生这种情况。

这就是vtable的工作原理。

如果派生类没有自己的vtable,它指向自己的重写成员函数而不是基类函数,那么虚拟分派就不能工作。

我不想要那里的多态性,我为什么要这样做,只是因为它派生出一个具有多态性的类?

但是你确实想要多态。你要求的。如果你从多态基类继承并覆盖它的虚函数之一,你声明了使用多态的意图。如果你不想要多态,你不会从多态基类继承。

 类似资料:
  • 其实,类似的问题这里问过,那里问过,但回答都不满意。代码示例是 输出为 关于 由于是虚函数,派生类不实现它,因此程序将调用; 则程序将调用; 是一个常规函数,程序将调用; 也是一个常规函数,程序将调用; 我不明白的部分来了,不是虚函数,是属于的指针,基本上只能访问中的函数!但输出是 相比之下,会像我想的那样调用。 在基类指针只能访问基类和虚函数中定义的函数的原则与实际输出之间似乎存在矛盾。原因也无

  • 我正在学习面向对象的C,并有一个关于虚拟/纯虚拟和多级继承的问题。 假设我有这样的简单代码: 我的理解是,除非getWidth被指定为虚拟,否则多态将使用“Base”类的函数。我的意思是r-的最终调用 在这种情况下,我注意到如果我删除Shape中的纯虚拟声明,我们会得到我刚才描述的行为。在基类中有一个纯虚函数会自动使该函数的所有定义都是虚的吗?

  • 我最近在读虚函数和虚析构函数,下面的问题引起了我的兴趣。 例如,我有以下继承链。 我知道基类的虚函数在派生类中默认是隐式虚的。所以,我认为这同样适用于析构函数。 我想知道,派生类的析构函数是否默认是虚拟的。如果没有,如果您提供一些解释,我将很高兴。

  • 本文向大家介绍什么是虚函数?什么是抽象函数?相关面试题,主要包含被问及什么是虚函数?什么是抽象函数?时的应答技巧和注意事项,需要的朋友参考一下 答: 虚函数:没有实现的,可由子类继承并重写的函数。Virtual CallSomeOne(); 抽象函数:规定其非虚子类必须实现的函数,必须被重写。public abstract void CallSomeOne();  

  • 我在嵌入式环境中使用 C,其中虚拟函数的运行时确实很重要。我读过关于可以内联虚拟函数的罕见情况,例如:内联虚函数真的是无意义的吗?接受的答案指出,只有在运行时已知确切的类时,例如在处理本地、全局或静态对象(不是指针或对基类型的引用)时,才有可能进行内联。我理解这背后的逻辑,但我想知道在以下情况下是否也可以内联: 从我的观点来看,编译器应该在编译时知道的最终类型,因为它是一个最终类。在这种情况下,是

  • 本文向大家介绍请你回答一下为什么析构函数必须是虚函数?为什么C++默认的析构函数不是虚函数?相关面试题,主要包含被问及请你回答一下为什么析构函数必须是虚函数?为什么C++默认的析构函数不是虚函数?时的应答技巧和注意事项,需要的朋友参考一下 将可能会被继承的父类的析构函数设置为虚函数,可以保证当我们new一个子类,然后使用基类指针指向该子类对象,释放基类指针时可以释放掉子类的空间,防止内存泄漏。