3

想象一下,我有一个类“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。我想知道是否有更简单/更好的解决方案。

谢谢

4

3 回答 3

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也接受 a 的代码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
};

//...

现在,需要 a 的代码BaseA需要重构为 a BaseI。该新代码也将能够接受 a DerivedA

于 2013-04-05T18:51:22.530 回答
0

您可以尝试使用 Curiously Recurring Template Pattern - 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 的所有元素或 DerivedA 实例中 DerivedItemA 的所有元素。没有必要混合。

这种方法没有任何混合:

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

但是,在不知道实际使用模式的情况下 - 很难猜出您需要什么。也许对于您的情况,两个独立的向量就足够了:

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

并为它们定义独立的函数。

于 2013-04-05T18:07:30.363 回答
0

我相信你需要在你的向量中有指针才能处理这个问题。我有点困惑传递给 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 中的指针执行操作。

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

于 2013-04-05T18:03:12.297 回答