【问题标题】:Preventing the instantiation of a class via pure virtual functions?防止通过纯虚函数实例化一个类?
【发布时间】:2012-10-13 10:55:06
【问题描述】:

我正在看我书中的以下代码:

class Shape
{
    public:
        Shape(){}
        ~Shape(){}
        virtual long getArea() = 0; // Pure virtual function
        virtual long getPerim() = 0;
        virtual void draw() = 0;
};

现在它说这些虚函数使类抽象(我从 Java 中理解),因此无法实例化该类。

但是,它说:“通过在类声明中包含一个或多个虚函数,类属于抽象数据类型。”

这是否意味着如果我声明一个具有 ONE 纯虚函数的类:

class Shape
{
    public:
        Shape(){}
        ~Shape(){}
        virtual long getArea() = 0; // Only pure virtual function
        virtual long getPerim(){}
        virtual void draw(){}
};

整个类都变得抽象了吗?因为如果一个类有 100 多个方法,如果我决定稍后将其抽象化,为每个方法编写 =0 会很乏味。

【问题讨论】:

  • 想想如果你可以用一个纯函数实例化一个类,然后尝试调用它会发生什么......
  • 如果一个类有 100 多个方法,那么您需要解决一些设计问题。
  • @juanchopanza 哈哈,是的,我是在假设。

标签: c++ class polymorphism abstract-class


【解决方案1】:

是的,单个纯virtual 方法足以使类抽象。

此外,如果没有其他方法适合纯析构函数,您始终可以将析构函数设为纯 virtual

另外,你的析构函数应该是virtual,因为你显然要从这个类继承。如果您计划通过指向基类型的指针删除派生类型的对象,则这是强制性的。

【讨论】:

  • 我仍然可以将方法放在非纯函数中,对吗?
  • @Ken:再澄清一点,你书中的类有三个纯虚方法,因为它们中的每一个都是纯虚方法是有意义的。如何计算面积、周长或如何绘制形状完全取决于具体的形状,因此这些方法必须由每个派生类编写,因此它们是纯虚的。
【解决方案2】:

你是对的,一个纯虚方法足以使类抽象。这意味着您必须在派生类中实现该方法才能实例化(派生类的)实例。

我对您的“具有 100 多种方法的课程”有疑问。通常这是设计非常糟糕的标志。

我也对您“对于每种方法都写 =0 很乏味”的态度有意见。首先,我不明白为什么写 =0 比写 {} 作为默认的无操作实现更乏味(如果该方法返回任何东西,就像getPerim() 那样,你可能会因为不返回而冒未定义的行为某物)。但主要是,业务逻辑决定是否存在默认行为,而不是编写工作量。

记住 Liskov 替换原则:虽然不能拥有基类的实例,但有人会拥有一个指针或引用,并在其上调用虚方法,而不必知道他们真正拥有的是什么类。 (顺便说一句,Liskov 是女性,名字叫 Barbara,并在 1983 年左右的某个时候陈述了这一原则。

顺便说一句,您的抽象基类几乎肯定应该有一个虚拟析构函数。

不会改变类状态的方法应该声明为 const。

【讨论】:

    【解决方案3】:

    将函数标记为纯函数不仅使类抽象,它还使任何不覆盖该函数的派生类也抽象。

    所以,如果你想强制派生类实现所有这些功能,那就让它们都纯。如果派生类只实现getArea 而不是其他两个是有意义的,那么只标记getArea 纯。在这个例子中,我怀疑它没有有意义,因为如果所有派生类都添加了一种计算面积的方法,那么基类仍然无法计算周长。

    【讨论】:

      【解决方案4】:

      将方法声明为纯虚拟意味着继承您的类的类必须实现该方法或将其保留为纯虚拟,在这种情况下,派生类也将是无法实例化的抽象类。

      此外,正如 Luchian 之前所说,您应该始终将析构函数声明为每个将被继承的类的虚拟函数。

      【讨论】:

      • “对于每个将被继承的类,你应该总是将析构函数声明为虚拟的。” 从字面上看,这是一个糟糕的建议。 Luchian 添加了一个细微差别,表明了这样做的目的:通过基指针使delete 安全(不是未定义的行为)。这是唯一一种“应该始终将析构函数声明为虚拟”的情况。对于所有其他类,多态删除不感兴趣,应该通过使析构函数受保护和非虚拟来简单地防止它。这可以防止未定义的删除,相反,不会用虚拟表来膨胀每个类。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-02-18
      • 1970-01-01
      • 2021-05-11
      • 2015-06-09
      • 1970-01-01
      • 2017-10-30
      • 1970-01-01
      相关资源
      最近更新 更多