纯虚函数与身体的用例?

时间:2010-04-09 16:52:25

标签: c++ virtual-functions

我最近才知道在C ++中,纯虚函数可以选择有一个体。

此类功能的实际使用案例是什么?

7 个答案:

答案 0 :(得分:41)

经典是一个纯粹的虚拟析构函数:

class abstract {
  public: 
    virtual ~abstract() = 0;
};

abstract::~abstract() {}

你使它变得纯粹,因为没有别的东西可以这样做,你希望这个类是抽象的,但你必须提供一个实现,因为派生类的析构函数明确地调用你的。是的,我知道,这是一本非常愚蠢的教科书例子,但同样这是一部经典之作。它必须出现在The C++ Programming Language的第一版中。

无论如何,我记不起真正需要实现纯虚函数的能力。对我而言,这个功能的唯一原因似乎是因为它必须明确禁止,而Stroustrup没有看到原因。

如果您觉得自己需要此功能,那么您的设计可能会出错。

答案 1 :(得分:35)

包含或不包含主体的纯虚函数仅仅意味着派生类型必须提供自己的实现。

如果派生类想要调用基类实现,则基类中的纯虚函数体很有用。

答案 2 :(得分:16)

抽象基类(使用纯虚函数)可能为它声明的纯虚函数提供实现的一个原因是让派生类有一个他们可以选择使用的简单“默认”。对于可以选择性覆盖的普通虚函数,这没有很多优势 - 事实上,唯一真正的区别在于你强迫派生类明确使用'默认'基类实现:

class foo {
public:
    virtual int interface();
};

int foo::interface() 
{
    printf( "default foo::interface() called\n");
    return 0;
};


class pure_foo {
public:
    virtual int interface() = 0;
};

int pure_foo::interface()
{
    printf( "default pure_foo::interface() called\n");
    return 42;
}

//------------------------------------

class foobar : public foo {
    // no need to override to get default behavior
};

class foobar2 : public pure_foo {
public:
    // need to be explicit about the override, even to get default behavior
    virtual int interface();
};

int foobar2::interface()
{
    // foobar is lazy; it'll just use pure_foo's default
    return pure_foo::interface();
}

我不确定是否有很多好处 - 也许在设计开始时使用抽象类的情况下,随着时间的推移发现很多派生的具体类都实现了相同的行为,所以他们决定将该行为移动到纯虚函数的基类实现中。

我认为将普通行为放入纯虚函数的基类实现中可能也是合理的,派生类可能会修改/增强/扩充。

答案 3 :(得分:8)

一个用例是从构造函数或类的析构函数中调用纯虚函数。

答案 4 :(得分:8)

全能的Herb Sutter,前C ++标准委员会主席did give 3 scenarios,您可以考虑为纯虚方法提供实现。

要亲自说 - 我发现它们都没有令人信服,并且通常认为这是C ++的语义瑕疵之一。似乎C ++不遗余力地构建和拆除抽象父vtable,而不仅仅是在构建/破坏子项时简单地暴露它们, and then 社区专家一致推荐{{3} }。

答案 5 :(得分:4)

虚拟函数与body和纯虚函数与body的唯一区别在于存在第二个阻止实例化。你不能用c ++标记类摘要。

答案 6 :(得分:3)

在学习OOD和C ++时,这个问题确实令人困惑。就个人而言,我脑子里常常出现的一件事是: 如果我需要一个Pure Virtual功能也有一个实现,那么为什么要把它变成“Pure”呢?为什么不将它只留下“虚拟”并获得好处并覆盖基础实现?

许多开发人员认为没有主体/实现是定义纯虚函数的主要目标/好处。这不是真的!在大多数情况下,缺乏身体是具有纯虚函数的逻辑结果。拥有纯虚函数的主要好处是定义合约!通过定义一个纯虚函数,你想要FORCE每个派生到ALWAYS提供他们自己的功能实现。这个“合同方面”非常重要,特别是如果您正在开发类似公共API的东西。使函数只是虚拟的不够,因为派生不再被迫提供自己的实现,因此您可能会失去合同方面(这可能是公共API的限制)。如通常所说:  “虚拟功能可以被覆盖,纯虚拟功能必须被覆盖。” 在大多数情况下,契约是抽象概念,因此对于具有任何实现的相应纯虚函数没有意义。

但有时候,因为生活很奇怪,你可能想要在衍生品之间建立一个强大的契约,并希望它们以某种方式从某些默认实施中受益,同时为合约指定自己的行为。即使大多数图书作者建议避免陷入这些情况,也需要提供安全网以防止最坏情况!一个简单的虚函数是不够的,因为可能存在逃避合同的风险。因此,C ++提供的解决方案是允许纯虚函数也能够提供默认实现。

上面引用的Sutter文章给出了具有纯虚拟功能和身体的有趣用例。