C ++:处理这种多重继承的最佳方法是什么?

时间:2013-12-09 23:17:58

标签: c++ multiple-inheritance

页面基本上是一个固定大小的类型数组 - 但它提供了其他功能,这对于这个问题并不重要。具体来说,每个页面都有一个recordOffset,这意味着页面的记录ID是顺序的,并从此索引开始(页面可以被视为较大数组的一个谨慎的任意段)

class AbstractPage
{
    protected:
        unsigned int recordOffset;

    public:
        AbstractPage(unsigned int recordOffset);
        virtual ~AbstractPage();

        // a mixture of pure and non-pure virtual functions
        virtual string toString() const;
        virtual unsigned int getCount() const = 0;
        virtual PageType pageType() const = 0;
};

class IntegerPage : public AbstractPage
{
    public:
        vector<int> data;

        IntegerPage(const vector<int>& data);
        virtual ~IntegerPage();

        // our concrete implementation
        virtual unsigned int getCount() const;
        virtual PageType pageType() const;
};

class FloatPage : public AbstractPage
{
    public:
        vector<float> data;

        FloatPage(const vector<float>& data);
        virtual ~FloatPage();

        // our concrete implementation
        virtual unsigned int getCount() const;
        virtual PageType pageType() const;
};

我不想为此使用模板,因为这些页面被使用喜欢这个;

LinkedList<AbstractPage> pages;

在大多数情况下,我将使用AbstractPage提供的界面方法与页面进行交互。当我需要直接读/写数据时,我将分别知道类型并使用:

dynamic_cast<FloatPage>(abstractPage).data[0] = 12.34;

到目前为止一切顺利,但这就是困境;我需要扩展每个类型以创建页面的索引版本:

class AbstractIndexedPage
{
    public:
        // this is instead of the recordOffset of AbstractPage
        vector<unsigned int> recordIds;
};

class IndexedIntegerPage : public AbstractIndexedPage, public IntegerPage
{
};

现在我希望能够做到这一点:

AbstractIndexedPage sort(const AbstractPage& page)
{
    // Sorting will swap around the data and therefore we need to keep track of the
    // record IDs in an Indexed page.
    // If the incoming concrete type is IntegerPage, the output will be
    // IndexedIntegerPage
}

问题是返回的对象没有AbstractPage的接口:

AbstractIndexedPage sortedPage = sort(originalPage);
sortedPage.getCount(); // can't do this!
dynamic_cast<AbstractPage>(sortedPage).getCount() // can do this, but pretty messy

从我所读到的除了select case之外的所有内容中的多重继承意味着你的代码基本上设计得很糟糕。在这种情况下,有两个非接口的多重继承,这两个类都有一个构造函数(和虚拟析构函数),但只会直接处理它们提供的实例变量。

我的选择是:

  1. AbstractIndexedPage扩展AbstractPage并使用virtual继承,因为现在有两个AbstractPage。但这将给我完整的界面。但这不是一个顽皮的黑客吗?
  2. 只需在datarecordIds中复制IndexedIntegerPageIntegerPage个实例变量即可提供相同的功能,而无需继承。
  3. 以不同的方式设计架构?
  4. 由于

2 个答案:

答案 0 :(得分:2)

您可以使用委派来完成这项工作。例如,在AbstractIndexedPage

class AbstractIndexedPage
{
    public:
        // this is instead of the recordOffset of AbstractPage
        vector<unsigned int> recordIds;
        AbstractClass* getPage() { return page;};
    private:
        AbstractClass *page;
};

并做类似的事情:

AbstractIndexedPage sortedPage = sort(originalPage);
sortedPage.getPage()->getCount(); // can't do this!

当然,验证所有可能的错误或遗漏。

P.S。有人会告诉你使用智能指针,我会同意他们,但为了简单起见,我只使用普通指针

答案 1 :(得分:1)

我打算在评论中发帖,但代码看起来很糟糕。您可以考虑在较低级别进行抽象:创建AnyType,并根据它创建一个页面类型:

union AnyType {
    float f;
    int i;
};

class AnyPage : public AbstractPage
{
public:
    enum PageDataType {FloatPage, IntPage};

    vector<AnyType> data;

    AnyPage(const vector<int>& data); //creates an 'IntPage'
    AnyPage(const vector<float>& data); //creates a 'FloatPage'
    virtual ~AnyPage();

    // our concrete implementation
    virtual unsigned int getCount() const;
    virtual PageType pageType() const;

private:
    PageDataType myType;
};

然后您可以创建AnyPage的链接列表,如您所说,您已经知道在要访问数据时要处理的页面类型:

anyPage.data[0].f = 12.34;

然后,对于索引变种,它不再是多重继承:

class AnyIndexedPage : public AnyPage
{
public:
    // this is instead of the recordOffset of AnyPage
    vector<unsigned int> recordIds;
};