利用值类型和引用的统一语法

时间:2015-03-26 00:59:56

标签: c++ inheritance design-patterns

我们假设我们有以下Base类,以及两个派生类Derived1Derived2

class Base {
// Some declarations ...
};

class Derived1 : public Base {
// Some declarations ...
public:
  vector<int> _array;
};

class Derived2 : public Base {
// Some declarations ...
public:
  vector<int> &_array;
};

也就是说,我们有一个公共类,但底层数据结构有不同的类型。

假设我们想要使用来自Base指针的统一接口来访问底层数组的各个元素。就像这样:

Base *bPtr = new Derived1(...);
int val = bPtr->index(3);

index中使用名为Base的纯虚函数是一种解决方案。但是,在这种情况下,我们需要在两个派生类中使用相同的int index(uint x) { return _array[x]; }实现。这很难看,我们无法在Base中实现该功能,因为它不了解_array

因此,我们必须(1)将_array的类型更改为相同类型(例如,更改为vector<int>*)并在index中实施Base }或(2)在Derived1Derived中有两个实现,以便使用公共接口。但是我承担不起(1)因为它会向Derived1添加额外的间接层,如果可能的话我想避免这种情况。拥有许多这样的成员变量会使(2)变得非常糟糕,因为这是很多样板和复制,并且难以维护。

我知道这两个index函数实际上是不同的函数,因为它们在不同的类型上运行。在许多其他场景中,Derived1Derived2需要单独的函数,因为它们具有不同的行为(并且将被编译为不同的目标代码)。但是在C ++的情况下,这些实现在语法上是相似的,所以我想知道是否有办法利用它。

一种可能的解决方案是拥有免费功能:

template <class T>
int index(const T &obj, uint x) {
  return obj._array[x];
}

我们声明indexDerived1Derived2的朋友。但是,这可能不会被认为是优雅的,因为它使用了朋友声明(同时声明朋友两次是重复的)。

因此,我的问题是: 是否有更优雅的方式来实现index,同时避免性能成本和代码重复?

附录: CRTP与我想要的非常接近,但它在删除现有类型Base<Derived1>时引入了两种新类型(Base<Derived2>是第一种,而Base是第二种)。这样的重构会触发代码库中的更多更改,这是不可取的(例如使函数/类使用Base模板函数/类,甚至将它们从头文件移动到源文件)。我想要的理想情况是不需要对代码库的其余部分进行更改。

1 个答案:

答案 0 :(得分:1)

使用CRTP

template <typename D, typename B = Base>
class CrtpBase : public B
{
    public:
    int index(size_t ind){return static_cast<D*>(this)->_array[ind];}
};

struct Derived1 : public CrtpBase<Derived1>
{
    vector<int> _array = {1,2,3};
};

struct Derived2 : public CrtpBase<Derived2>
{
    vector<int> _arr = {4,5,6};
    vector<int>& _array = _arr;
};

DEMO