【问题标题】:C++ multiple inheritance and pure functionsC++ 多重继承和纯函数
【发布时间】:2014-06-02 21:59:41
【问题描述】:

我对“多重继承问题”有点困惑。考虑以下代码块:

#include <iostream>

struct iface
{
    virtual void foo () = 0;
    virtual ~iface () {}
};

struct wrapped
{
    virtual void foo ()
    {
        std::cerr << "wrapped\n";
    }
};

struct impl : public wrapped, public iface
{
};

iface* factory ()
{
    return new impl;
}

int main ()
{
    iface *object = factory ();

    object->foo();

    delete object;

    return 0;
}

这是从一些使用 pimpl 习惯用法的代码中抽象出来的。这个想法是wrapped 是一个复杂的类,有各种各样的花里胡哨。 iface 只是使wrapped 的一个特定方面可见,factory() 函数通过使用wrapped 构建一个实现ifaceimpl 类。在我的真实代码中,wrapped 类来自一个具有巨大标题树的库,因此我在一个单独的编译单元中定义了impl,以避免我的应用程序的其余部分不得不将它们拉入。

反正我贴的东西编译不通过,报如下错误:

$ g++ -o test test.cc
test.cc: In function ‘iface* factory()’:
test.cc:23:16: error: cannot allocate an object of abstract type ‘impl’
     return new impl;
                ^
test.cc:17:8: note:   because the following virtual functions are pure within ‘impl’:
 struct impl : public wrapped, public iface
        ^
test.cc:5:18: note:     virtual void iface::foo()
     virtual void foo () = 0;
                  ^

显然,我可以通过在impl 中编写foo 的具体实现来避免该错误,该实现转发到wrapped::foo(),但我不明白为什么编译器不从@987654335 中获取实现@类。

我假设 iface 中的“foo”和 wrapped 中的“foo”在为 impl 进行名称解析时最终会有所不同(这是正确的词),但我真的不明白为什么。

有人可以解释发生了什么吗?

【问题讨论】:

  • 正是 那个 正在发生:wrapped::foo() 不会神奇地映射到 iface::foo()。它们是两种截然不同的类型。当用作“iface”时,编译器必须能够解析 iface::foo(),它不能只是猜测继承的 Wrapped::foo() 是要调用的,你必须给出一个实施。
  • 是的,这是有道理的。我想问题是implifacewrapped 的“下游”,因此无法说服他们两个他们的foo 函数应该具有相同的解析名称(如果这是正确的术语)。感谢您的帮助。

标签: c++ multiple-inheritance pure-virtual


【解决方案1】:

如果类的任何虚函数是纯虚函数,则该类是抽象的。 类 impl 有两个同名的成员函数

iface::foo

wrapped::foo

类impl的第一个成员函数是纯虚的,所以类是抽象的。编译器可能不会创建抽象类的对象。

【讨论】:

  • 对。抱歉,我的问题可能不够清楚。我想了解的是是否可以声明我的impl 类,以便两个函数具有相同的名称。显然不是。
  • 无论如何,谢谢。这是正确的,并且(根据 Willem van Rumpt 的评论)我现在明白发生了什么。谢谢你们的帮助。
【解决方案2】:

impl 有两个完全独立的方法,iface::foo(纯方法)和wrapped::foo。没有名称解析——虚函数调用由一个名为 vtable 的结构分派,该结构包含指向实现的指针。一个类对于它的每个直接祖先都有单独的 vtable,至少在没有虚拟继承的情况下是这样。来自不同祖先的同义虚函数最终出现在不同的 vtable 中;编译器无法“组合”它们。 C++ 没有 mixins。

显然,我可以通过在 impl 中编写 foo 的具体实现来避免该错误,该实现转发到 Wrapped::foo()

更好的是,不要使用双重继承——做类似的事情

struct impl : public iface
{
    virtual void foo ()
    {
        wr.foo ();
    }
private:
    wrapped wr;
};

【讨论】:

  • 非常认真:为什么您认为存储对象是更好的解决方案?我了解多重继承的一些问题(菱形图等),但我认为上面的示例正是多重继承旨在解决的问题。我应该说我来自 lisp 背景,其中对象系统相当灵活(并且相应地更慢),所以有些“不要那样做!” C++ 圈子中的建议对我来说相当混乱。
  • 你不应该使用多重继承,因为它很混乱并且没有实现简单聚合无法完成的事情。 C++ 的一些特性设计得很差。如果wrapper 很重,您可以使用指针。
  • 好的。我们将从根本上不同意这种设计选择,所以我将把话题留在那里。谢谢你的澄清。
猜你喜欢
  • 2012-01-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-07
  • 1970-01-01
  • 2014-11-06
  • 1970-01-01
相关资源
最近更新 更多