【问题标题】:Do ALL virtual functions need to be implemented in derived classes?所有的虚函数都需要在派生类中实现吗?
【发布时间】:2017-07-09 15:24:16
【问题描述】:

这似乎是一个简单的问题,但我在其他任何地方都找不到答案。

假设我有以下内容:

class Abstract {
public:
    virtual void foo() = 0;
    virtual void bar();
}

class Derived : Abstract {
public:
    virtual void foo();
}

Derived 类不实现 bar() 函数可以吗? 如果不是我的所有派生类都需要 bar() 函数怎么办,但有些需要。 抽象基类的所有虚函数都需要在派生类中实现,还是只需要纯虚函数? 谢谢

【问题讨论】:

    标签: c++ inheritance


    【解决方案1】:

    只有纯虚方法必须在派生类中实现,但您仍然需要其他虚方法的定义(而不仅仅是声明)。如果你不提供,链接器很可能会抱怨。

    因此,只需将{} 放在可选的虚拟方法之后即可为您提供一个空的默认实现:

    class Abstract {
    public:
        virtual void foo() = 0; // pure virtual must be overridden
        virtual void bar() {}   // virtual with empty default implementation
    };
    
    class Derived : Abstract {
    public:
        virtual void foo();
    };
    

    不过,更多涉及的默认实现将进入单独的源文件。

    【讨论】:

      【解决方案2】:

      派生类不必自己实现所有虚函数。他们只需要实现 pure 个。1 这意味着问题中的Derived 类是正确的。它继承来自其祖先类Abstractbar 实现。 (这里假设Abstract::bar 在某处实现。问题中的代码声明了方法,但没有定义它。您可以像Trenki's answer 所示内联定义它,也可以单独定义它。)


      1 即便如此,也只有当派生类将被实例化时。如果派生类没有直接实例化,而只是作为更多派生类的基类存在,那么那些类负责实现其所有纯虚方法。层次结构中的“中间”类允许保留一些未实现的纯虚方法,就像基类一样。如果“中间”类确实实现了纯虚方法,那么它的后代将继承该实现,因此他们不必自己重新实现。

      【讨论】:

      • 即使这样(纯虚函数的实现)也只有当它们被实例化时(与作为抽象基类本身相反)。
      • 我就是这么想的。但是我在我的项目中这样做,我收到一个链接错误,说 Derived::bar(); 有一个“未解析的外部符号”;但是我从来没有在 Derived 中声明 bar,那么为什么链接器要寻找函数体呢?
      • @pixelpusher 当然Derived::bar 有一个函数体,也就是Abstract::bar。因此,似乎定义的翻译单元(甚至在任何地方都定义过?)没有链接到调用它的翻译单元。
      • @Rob: They only need to implement the pure ones. 这是误导。派生类也不一定需要实现虚函数。
      • 感谢您的帮助,但 @trenki 击中了头。虽然你也是正确的 Christian Rau,因为它没有被定义。
      【解决方案3】:

      是的,派生类必须覆盖父类中纯虚拟的函数是正确的。具有纯虚函数的父类之所以称为抽象类,是因为它的子类必须给出自己的纯虚函数体。

      对于普通的虚拟功能:- 没有必要进一步覆盖它们,因为某些子类可能具有该功能,而某些子类可能没有。

      虚函数机制的主要目的是运行时多态性,纯虚函数(抽象类)的主要目的是否是强制必须与自己的主体同名的函数。

      【讨论】:

        【解决方案4】:

        ISO C++ 标准规定必须定义一个类的所有非纯虚方法。

        简单地说规则就是:
        如果您的派生类覆盖了 Base 类的虚方法,那么它也应该提供一个定义,如果没有,那么 Base 类应该提供该方法的定义。

        根据代码示例中的上述规则,virtual void bar(); 需要在 Base 类中定义。

        参考:

        C++03 标准:10.3 虚函数 [class.virtual]

        在一个类中声明的虚函数应在该类中定义或声明为纯(10.4),或两者兼而有之;但不需要诊断 (3.2)。

        所以要么你应该将函数设为纯虚函数,要么为它提供一个定义。

        gcc faq 也记录了它:

        ISO C++ 标准规定必须定义一个类的所有非纯虚方法,但不需要对违反此规则[class.virtual]/8 进行任何诊断。基于此假设,GCC 只会在定义其第一个此类非内联方法的翻译单元中发出类的隐式定义的构造函数、赋值运算符、析构函数和虚拟表。

        因此,如果您未能定义此特定方法,链接器可能会抱怨缺少明显不相关符号的定义。不幸的是,为了改善此错误消息,可能需要更改链接器,但并非总是如此。

        解决办法是确保定义了所有非纯的虚方法。请注意,即使声明为纯虚拟[class.dtor]/7,也必须定义析构函数。

        【讨论】:

          【解决方案5】:

          是的,这很好......您只需要实现任何纯虚函数即可实例化从抽象基类派生的类。

          【讨论】:

            猜你喜欢
            • 2012-02-14
            • 2013-06-02
            • 2018-10-14
            • 1970-01-01
            • 2011-06-21
            • 2015-10-24
            相关资源
            最近更新 更多