【问题标题】:Can a class still be pure abstract if it has a non-pure destructor?如果一个类有一个非纯析构函数,它还能是纯抽象的吗?
【发布时间】:2011-09-28 15:49:18
【问题描述】:

我正在做一个练习,要求我采用一个基类 Rodent 并将其变成一个纯抽象类。我对纯抽象类的理解是,它充当接口,只包含纯虚函数。虽然这是一个简单的练习,但我对本书提供的解决方案有疑问:

class Rodent
{
    public:

    virtual ~Rodent() {cout << "Destroy rodent" << endl;}
    virtual void run() = 0;
    virtual void squeak() = 0;
};

如您所见,作者为析构函数添加了一个虚拟定义。加入这个定义是不是意味着这是一个抽象类而不是一个“纯”抽象类?

【问题讨论】:

  • 我明白,我想知道它是否仍然是“纯”摘要。
  • 这个问题中最不有趣的一点是,pure abstract class 不是 C++ 概念,因此它很大程度上取决于您对该术语的定义是什么(比较with:纯虚函数,标准中定义的具有精确含义的)

标签: c++ class abstract pure-virtual


【解决方案1】:

一个抽象类必须包含至少一个纯虚函数。

你的类已经有两个纯虚函数run()squeak(),所以你的类是抽象的,因为这两个纯虚函数。

您不能创建此类的任何对象。

编辑:

纯抽象类,是一个专门具有纯虚函数(并且没有数据)的类。 由于您的析构函数不是纯虚拟的,因此您的类不是纯抽象类。

【讨论】:

  • 我同意你的观点,这仍然是一个抽象类,你的定义很完整,但为了完整起见:当虚函数没有定义时,它被称为“纯”,如果它有定义只是一个虚函数(方法真的)。谢谢!
  • 是的,纯虚函数可以有定义,但是这个例子中的析构函数不是纯的。问题不在于该类是否是抽象的。这是关于它是否是抽象的。
  • @thamurath:这是不正确的。纯虚函数可以有定义,只是C++不允许定义内联到类中。函数定义的存在与否不会改变函数是否为纯虚函数这一事实。
  • 问题是关于“纯抽象”类,而不是纯虚函数或抽象类。
  • @thamurath:这并不完全正确。如果使用 pure-specifier = 0 声明成员函数,则它是纯虚函数。与您的定义不同的是,纯虚函数 可以有一个定义:struct test { virtual void f() = 0; }; void test::f() {} 是完全有效(且可用)的代码。这不仅仅是一个虚拟函数,因为testf 的存在抑制了test 类型对象的实例化——这就是纯虚拟 的含义.
【解决方案2】:

根据 C++ 的规则,每个类都需要一个析构函数。如果你不提供,编译器会为你生成一个。

在我看来这仍然是一个纯粹的抽象类,因为析构函数是规则的一个例外。

【讨论】:

  • 如果析构函数设置了一个全局变量怎么办?如果构造函数打开一个文件进行日志记录怎么办?当然,这是一个非常愚蠢的定义问题,但在这种情况下,我不确定我是否同意你的看法:-)
  • @Nemo:这只是您认为“纯抽象类”应该暗示什么的问题。如果您想使用该术语来指定(除了其他约束之外)具有无操作析构函数的类,则以这种方式定义它。马克和提问者教科书的作者,以另一种方式定义它。这就是写一本书的好处,你可以说出其中的技术术语是什么意思:-)
  • 使用“所有成员都是纯虚函数”有什么问题?
  • @JoeGauterin,析构函数是一个成员,它不能是纯虚拟的,因为 C++ 的规则不允许它。否则你的定义很好。
  • @Mark Ransom:析构函数可以是纯虚拟的 - struct foo{ virtual ~foo()=0;}; inline foo::~foo(){}
【解决方案3】:

virtual 关键字对于析构函数的含义有些不同。当基类的 dtor 是虚拟的时,这意味着调用继承层次结构中的 所有 dtor。你不能真的像这样覆盖它。

通常你会认为它是空的:

class Rodent {
public:
  virtual ~Rodent() {}
  virtual void run() = 0;
  virtual void squeak() = 0;
};

我觉得差别很小。有可能因为空体是无操作的,编译器可以通过一些语言律师法规忽略它。

我认为你称自己为纯虚拟不会混淆任何人。

【讨论】:

  • 析构函数的空体很有用,因为它会被所有派生类调用;如果在编译时知道它是空的,编译器可以优化它。
  • @MarkRansom 我明白为什么它很好、有用等。是否有严格的规范定义是一回事,我对此没有答案。不过,我认为两者在理解正在发生的事情方面没有概念上的区别。
【解决方案4】:

据我了解,C++ 标准并未指定纯抽象类。然而,C++0x (n3290) 指定了抽象类

10.4/2 一个类是抽象的,如果它至少有一个纯虚 功能。

纯抽象类是一个约定俗成的术语,描述了一个抽象类

  • 没有数据成员
  • 没有任何非纯虚函数
  • 没有任何具体功能

由用户指定。

所以,根据这个约定,class Rodent 不是一个纯抽象类

【讨论】:

    【解决方案5】:

    考虑像这样实现你的界面

    class Rodent {
    public:
      virtual ~Rodent() = 0;
      virtual void run() = 0;
      virtual void squeak() = 0;
    };
    inline Rodent::~Rodent() {}
    

    将您的析构函数指定为纯虚拟并内联实现可避免在导出子类时在 MSVC2010 中出现以下警告:

    warning C4275: non dll-interface class 'A' used as base for dll-interface class 'B'
    

    【讨论】:

      【解决方案6】:

      是的,它不再是一个纯粹的类了。一个纯粹的抽象类没有任何功能,它只是提供一个框架。 cout 是功能。

      【讨论】:

        猜你喜欢
        • 2019-10-05
        • 2011-03-31
        • 2019-04-20
        • 1970-01-01
        • 2016-03-01
        • 1970-01-01
        • 2011-03-21
        • 2019-12-08
        • 2011-09-28
        相关资源
        最近更新 更多