【问题标题】:Why can't we create an instance of an abstract class?为什么我们不能创建抽象类的实例?
【发布时间】:2011-07-05 03:10:00
【问题描述】:

我在很多地方发现:

  • 抽象类是应该用作基类的类。
  • 抽象类是具有至少一个纯虚函数的类。

但我一直在想的一件事是为什么我们不能创建一个抽象类的实例? Internet 上的许多地方都说创建实例没有意义,或者有人说它们应该用作基类。但是为什么创建抽象类的实例会出错呢?

【问题讨论】:

  • 如果我让你画一只猫,那么你可以很容易地画一只猫(如果你画得好:)),但是如果我让你画一只猫一只动物,你会画吗?你可以说到底是哪种动物?同样,您可以创建具体类 Cat 的对象,但不能创建抽象类 Animal 的对象。抽象类背后的整个想法是代码可重用性,以便可以在 Animal 类中实现 Cat 类和 Dog 类的共同行为。
  • 虽然 C++ 禁止创建抽象类,但您可能想知道 Delphi 不禁止。如果你尝试它,编译器会警告你,但它会编译,并且实例化会运行得很好。甚至有一些简单的方法可以避免警告。不过,调用抽象方法会引发异常。
  • @Rob:有趣的是,Delphi 就是这样工作的。能够实例化一个抽象类有什么特别的优势(即,你曾经使用过它吗)?它是如何在运行时调用构造函数的?
  • @Cody,没有用例。允许它是不能阻止它的要求。 Delphi 允许类引用,其中变量代表类本身,您可以在变量上调用(非实例)方法。存储对抽象类的引用是完全合法的——编译器在赋值时不知道你是否会调用它的抽象方法——所以它不能禁止赋值。您可以调用的方法包括构造函数。由于编译器无法阻止抽象类的间接实例化,因此禁止直接实例化毫无意义。

标签: c++ oop abstract-class language-design


【解决方案1】:

您的void bar()=0; 无效——=0 表示法只能用于虚函数。

抽象类的全部意义在于它是抽象的——你定义了一个接口但没有定义一个实现。如果没有实现,实例化类不会产生有意义或有用的结果。如果实例化该类的对象确实/有意义,那么您根本不想首先使用抽象类。

例如,考虑设备驱动程序。我们可能有一个抽象存储设备的驱动程序。我们为该设备定义了一些功能,例如读取和写入数据。该抽象类使任何想要读取/写入数据的代码都能够使用派生自该抽象类的具体类。

我们不能只是实例化我们的抽象存储设备。相反,我们需要一个具体的对象,如拇指驱动器、磁盘驱动器等,来实际读取/写入。需要具体类,因为我们需要特定于实际设备的代码来执行我们在抽象基础中定义的命令。我们的抽象存储类只有读取或写入,但读取或写入,我们需要特定设备的驱动程序。一个人可能知道如何与 SATA 硬盘驱动器通信,而另一个人知道如何与 USB 拇指驱动器通信,而另一个人知道如何读取或写入 SD 卡。然而,我们不能,只是说“我要创建一个抽象存储设备”,然后在不定义将“写入”命令转换为的实际代码(例如) 正确的信号通过 SATA、USB、Firewire 等,将数据传输到真正的驱动器上。

因此,尝试实例化我们的抽象类是没有意义的,也是不允许的。我们只使用抽象基类,以便系统的其余部分可以统一处理所有设备。其余的代码并不关心信号之间的不同——它只是看到一堆磁盘驱动器,并且可以与所有这些驱动器一起工作,即使通过 USB 读取数据的细节与读取完全不同通过火线(例如)。

【讨论】:

    【解决方案2】:

    抽象类表示不够具体而无法实例化的东西。例如,如果有人要求您创建车辆怎么办?你必须问,“什么样的车辆?”你不知道是要制造汽车、雪橇还是航天飞机。没有“车辆”这样的物体。然而,“车辆”是一种有用的抽象,可用于对对象进行分组,指示它们之间的共同行为。这就是抽象类的用途。

    【讨论】:

      【解决方案3】:

      抽象类不仅仅是一个接口。它可能有数据成员。它可能具有非纯虚拟或根本非虚拟的成员函数。即使是纯虚函数也可能有一个主体,提供默认实现。因此,这与实例化抽象类的物理上的不可能性无关。

      重点是纯虚函数是必须被派生类覆盖的虚函数。这意味着必须定义派生类,强制实现的方法是禁止抽象类的实例化。

      抽象类不够具体,无法实例化。不一定是因为它缺少函数的定义,因为它可能没有缺少它。它不够具体,因为它代表了一个抽象概念,在实例化之前必须使其更加具体。

      【讨论】:

      • 这是不正确的。一个虚函数可能有一个主体。根据定义,“纯”虚函数是定义为“= 0”的虚函数(即不提供定义的虚函数)。
      • 恕我直言,不正确的是你。在 C++ 中,纯虚函数可能有一个主体。 stackoverflow.com/questions/2089083/…
      【解决方案4】:

      这就是抽象类的重点:一些细节必须由实现者提供。

      想一想:如果你可以直接实例化一个类,那么将它标记为抽象的意义何在?那么它就和任何其他类没有什么不同了。

      【讨论】:

        【解决方案5】:

        抽象类不能实例化的原因是:如果你执行纯虚函数怎么办?这将是一个严重的错误,最好在编译时捕获它而不是在运行时捕获。

        【讨论】:

        • 其实一个纯虚函数可能有一个体。尽管如此,它必须被派生类覆盖。不能实例化一个抽象类与其说是物理上的不可能性,不如说是关于强制重写纯虚函数。
        • 你可以执行一个已经定义好的纯虚函数,没有任何错误或任何东西。
        • @Dima,如果一个虚函数有一个主体,它就不是“纯”的。
        • @Eugen,您不能执行纯虚函数(在运行时),尽管您可以创建一个函数来调用另一个在当前范围内是纯虚函数的函数(但该调用实际上在为该函数提供实现的派生类)。
        • @Michael:这样的事情是完全合法的:struct Base { virtual void foo() = 0 {...}}; struct Derived : Base { void foo(){ Base::foo(); } };.
        【解决方案6】:

        在抽象类中没有给出方法定义,只提供结构。如果我们可以实例化抽象类并调用这些方法,那将是一团糟。抽象类用于维护代码的设计模式。

        【讨论】:

        • 不正确。纯虚函数可以有定义。并且一个抽象类可以有非纯虚函数或非虚函数。
        【解决方案7】:

        只有 Chuck Norris 可以实例化抽象类。

        https://api.chucknorris.io/jokes/ye0_hnd3rgq68e_pfvsqqg

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-03-08
          • 1970-01-01
          • 1970-01-01
          • 2019-04-07
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多