【问题标题】:virtual functions and abstract classes虚函数和抽象类
【发布时间】:2011-04-16 19:09:13
【问题描述】:

我在我的书中读到:

抽象类是专门设计用作基类的类。一个抽象类至少包含一个纯虚函数。在类声明中的虚成员函数声明中使用纯说明符 (= 0) 来声明纯虚函数。

抽象类必须要有虚函数吗?为什么?

纯虚函数和虚函数有什么区别,需要什么?

【问题讨论】:

    标签: c++ visual-c++


    【解决方案1】:

    纯虚函数指定了一个接口,必须在派生类中重写该接口才能创建派生类的对象。

    一个(非纯)虚函数指定一个接口,可以在派生类中被覆盖,但基类提供该接口的默认实现。

    对于大多数实际用途,是的,抽象基类必须包含至少一个虚函数。抽象基类的全部意义在于指定由派生类实现的接口。该接口是根据许多可以调用的虚拟函数来指定的。没有虚函数,你就没有指定一个接口,这使得抽象基类很难完成很多事情。

    【讨论】:

      【解决方案2】:

      如果您使用抽象类,这意味着您不想错误地实例化此类。而且你必须在那个类中使用纯虚函数。但是在类中声明或编写函数是你的选择。您也可以在派生类中编写函数。

      【讨论】:

        【解决方案3】:

        不同之处在于您无法实例化抽象类 - 它充当interface

        【讨论】:

        • 只是好奇(我不是怀疑你),当我使用 C# 接口概念时,接口有一个到实现类的链接,例如在使用观察者模式时。那么另一个类如何能够通过抽象类(又名接口)“访问”派生类?
        • 这在C++中相当简单——派生类IS-A基类,调用者只持有一个指针或对它的基部分的引用。
        • 例如,一个类的每个实例都包含对虚函数表的引用,因此给定一个实例和一个方法调用(该表中的偏移量),可以“到达”派生类的代码
        【解决方案4】:

        要成为抽象类,必须有一个纯虚函数。只有虚函数可以是纯的,因为它可以被覆盖,因此它对多态很有用。纯非虚函数没有意义,因为它什么都不做,也不能被覆盖,所以没用,也不存在:)

        【讨论】:

          【解决方案5】:

          是的,它必须至少有一个纯虚函数。

          如果您的基类的所有虚函数都有一个实现,并且您仍然希望将其抽象化,您可以使用纯虚析构函数

          class MyAbstractClass
          {
              virtual ~MyAbstractClass() = 0;
          
              virtual void f() 
              {
                  IHaveAnImplementation(); 
                  SoICannotBePure();
              }
          };
          
          // The destructor can unfortunately not be defined inline
          MyAbstractClass::~MyAbstractClass() {}
          

          这只是一个方便:纯析构函数并不是真正的纯函数,因为它有一个定义。它只是一个标记,表示该类不能被实例化,尽管它没有其他抽象函数。

          【讨论】:

            【解决方案6】:

            纯虚表示该方法没有实现,因此它强制任何非抽象子类提供该实现。

            【讨论】:

            • 不,纯虚拟意味着它必须在派生类中有一个实现,但它仍然可以在基类中有一个实现
            【解决方案7】:

            在 C++ 中,使类抽象的唯一方法是在其中放置至少一个纯虚函数。编译器不会让你实例化一个包含纯虚函数的类,因为那样你就会有一个没有定义的函数的对象。可能有一些神秘的方法可以解决这个问题,但这是标准做法。

            纯虚函数和虚函数的区别在于纯虚函数不指定方法的实现。 =0 语法告诉编译器该类没有为函数提供定义,这使函数成为纯虚函数并使类抽象。任何从抽象基类派生的类都必须定义纯虚函数,否则子类也将是抽象的。

            “非纯”虚函数是用 virtual 关键字标记的,但在基类中提供了该函数的定义。这意味着基类提供了函数的实现,如果需要,任何子类都可以覆盖它。当您使用指向派生类对象的基类指针时,virtual 关键字允许多态性工作。

            【讨论】:

              【解决方案8】:

              可以在派生类中重写虚函数。

              必须在派生类中重写纯虚函数。

              纯虚函数的类不能被实例化。

              【讨论】:

                【解决方案9】:

                抽象类必须要有虚函数吗?为什么?

                这取决于您使用的定义。标准用途

                一个类是抽象的,如果它至少有一个纯虚函数。

                所以是的,这是强制性的。非正式地,您可以使用另一个定义,但在 C++ 上下文中可能会造成混淆。

                纯虚函数和虚函数有什么区别,需要什么?

                纯虚拟成员:

                • 必须在所有非抽象派生类中重写

                • 可以不定义(但可以给出定义,在纯虚析构函数的情况下甚至是强制性的)。

                【讨论】:

                • 纯虚函数可能有实现
                • @Chris Card,作为非英语母语人士可能存在问题。我写了“may not have”来表示可以不给出定义,并且会写“must not have”来表示禁止给出定义。我会澄清的。
                • 好吧,我明白了,“可能没有”是模棱两可的,但是它是否有实现并不是“纯虚拟”含义的一部分
                【解决方案10】:

                纯虚函数是必须被任何具体(即非抽象)派生类覆盖的函数。这在声明中用成员函数声明中的语法" = 0" 表示。

                示例:

                class AbstractClass {
                public:
                  virtual void AbstractMemberFunction() = 0; // Pure virtual function makes
                                                             // this class Abstract class.
                  virtual void NonAbstractMemberFunction1(); // Virtual function.
                
                  void NonAbstractMemberFunction2();
                };
                

                一般而言,抽象类用于定义实现,并旨在由具体类继承。这是在类设计者和该类的用户之间强制签订合同的一种方式。如果我们希望从抽象类创建一个具体类(一个可以实例化的类),我们必须为基类的每个抽象成员函数声明和定义一个匹配的成员函数。否则,如果基类的任何成员函数未定义,我们将创建一个新的抽象类(这有时会很有用)。

                【讨论】:

                  猜你喜欢
                  • 2020-07-01
                  • 1970-01-01
                  • 2016-11-29
                  • 2020-06-19
                  • 2019-04-08
                  • 2023-03-14
                  • 1970-01-01
                  • 2013-01-15
                  • 2019-04-20
                  相关资源
                  最近更新 更多