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

What is the best way to handle a collection of derived objects in a derived class

本文关键字:派生 最佳 方法 是什么 对象 处理 集合      更新时间:2023-10-16

假设我有一个类'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(); }
};

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

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

谢谢

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

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的东西。

你拥有所有的类吗?如果是这样,你可以重构成一个模板基类。

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的代码,那么你可能需要将它们修改为模板函数/类。

否则,您将需要向量的某种"多态"基对象。您可以查看从异构std::list中检索数据(或者我的后续问题:unique_ptr成员,私有复制构造函数与移动构造函数)来获取这样一种方法。


作为多态物品的替代品,你可以为你的基类定义一个接口。

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

您可以尝试使用好奇循环模板模式- CRTP:

现场演示

#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的所有元素,或者包含DerivedItemA实例化中DerivedA的所有元素。没有必要混在一起。

在这种方法中没有任何混合:

  • Base只有vector<<strong>Item>提供m1方法
  • DerivedBase只有vector<<strong>DerivedItem>提供m1m2方法。

然而,如果不知道真正的使用模式-很难猜测您需要什么。也许对于您的情况,两个独立的向量就足够了:

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

并为它们定义独立的函数