处理派生类中派生对象集合的最佳方法是什么

时间:2013-04-05 17:30:25

标签: c++ collections derived-class

想象一下,我有一个“BaseA”类,其中包含项目'ItemA'的集合。 现在我想扩展'BaseA'以增加额外的功能,所以我从'BaseA'派生'DerivedA'。  'DerivedA'的一个特点是它必须处理更复杂的'DerivedITemA'项而不是'ItemA'项。

class BaseA {
protected:
    vector<ItemA> x;
    void m1(int i) { x.m1(i); }
};

class ItemA {
protected:
    void m1(int i) { ... }
};

class DerivedItemA : public ItemA {
    void m2(int i) { ... }
};

现在我想处理这类事情:

class DerivedA : public BaseA {
    vector<DerivedItemA> x;
    void m2(int i) { x[i].m2(); }
};

即。让我的Derived类处理派生项。上面的x定义是不正确的,因为它与BaseA中的那个冲突。但我的想法是,我希望能够重用BaseA中处理x的所有方法,只要它们处理ItemA元素并在DerivedA中使用扩展方法来处理DerivedItemA类型数据的额外复杂性

有什么建议吗?我目前的想法是为x定义一个新的数据类型(例如VectorOfItemA)并从它派生VectorOfDerivedItemA。我想知道是否有更简单/更好的解决方案。

由于

3 个答案:

答案 0 :(得分:0)

我相信你需要在你的向量中有指针才能处理这个问题。我有点困惑传递给m1和m2的值,因为我似乎是一个索引,但这是我的猜测:

class BaseA {
protected:
    vector<ItemA*> x;
    void m1(int i) { x[i]->m1(i); }
};

class ItemA {
protected:
    void m1(int i) { ... }
};

class DerivedItemA : public ItemA {
    void m2(int i) { ... }
};

class DerivedA : public BaseA {
    vector<DerivedItemA*> y; //don't shadow the base class vector!
    void m2(int i) { y[i]->m2(i); }
};

然后,当您在DerivedA中添加项目时,将其添加到x和y。这样BaseA可以对x中的指针执行操作,DerivedA可以在y中的指针上执行此操作。

编辑:您还需要提供一个虚拟方法来添加项目,否则您可能会将添加到BaseA.x的内容添加到DerivedA.y中。

答案 1 :(得分:0)

您可以尝试使用奇怪的重复模板模式 - CRTP

live demo

#include <iostream>
#include <ostream>
#include <vector>

using namespace std;

struct Item
{
    void m1(int i)
    {
        cout << "m1(" << i << ")" << endl;
    }
};
struct DerivedItem : Item
{
    void m2(int i)
    {
        cout << "m2(" << i << ")" << endl;
    }
};

template<typename Derived>
struct IBase
{
    void m1(int i)
    {
        for(auto &&z : static_cast<Derived*>(this)->x)
        {
            z.m1(i);
        }
    }
};
template<typename Derived>
struct IDerivedBase: IBase<Derived>
{
    void m2(int i)
    {
        for(auto &&z : static_cast<Derived*>(this)->x)
        {
            z.m2(i);
        }
    }
};

struct Base : IBase<Base>
{
    vector<Item> x;
};
struct DerivedBase : IDerivedBase<DerivedBase>
{
    vector<DerivedItem> x;
};

int main()
{
    Base b;
    b.x.resize(3);
    DerivedBase d;
    d.x.resize(1);

    b.m1(11);
    d.m1(22);
    d.m2(33);
}

输出是:

m1(11)
m1(11)
m1(11)
m1(22)
m2(33)
  

Vector将在BaseA实例化中包含所有元素作为ItamA,或者在DerivedA实例中包含DerivedItemA的所有元素。没有必要混合。

这种方法没有任何组合:

  • 基础只有向量&lt; 项目&gt;提供 m1 方法
  • DerivedBase 只有向量&lt; DerivedItem &gt;提供 m1 m2 方法。

但是,如果不了解真实的使用模式 - 很难猜出你需要什么。也许对于你的情况,两个独立的向量就足够了:

vector<Item> x1;
vector<DerivedItem> x2;

并为它们定义独立的功能。

答案 2 :(得分:0)

你拥有所有课程吗?如果是这样,您可以改为重构为模板基类。

template <typename ITEM>
class BaseT {
protected:
    vector<ITEM> x;
    void m1(int i) { x[i].m1(); }
};

typedef BaseT<ItemA> BaseA;

class DerivedA: public BaseT<DerivedItemA> {
    void m2(int i) { x[i].m2(); }
};

如果您打算重复使用BaseA同时接受DerivedA的代码,那么您可能需要将它们修改为模板函数/类。

否则,您将需要某种矢量的“多态”基础对象。您可以查看Retrieve data from heterogeneous std::list(或我的后续问题:unique_ptr member, private copy constructor versus move constructor),了解其中一种方法。


作为多态项目的替代方案,您可以为基础定义接口。

class BaseI {
protected:
    virtual void m1(int) = 0;
    //... other interfaces
public:
    virtual ~BaseI () {}
    //... other public interfaces
};

template <typename ITEM>
class BaseT : public BaseI {
protected:
    vector<ITEM> x;
    void m1(int i) { x[i].m1(); }
    //...implement the other interfaces
};

//...

现在,需要重构代码BaseA以取代BaseI。新代码也可以接受DerivedA