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

Exploiting uniform syntax of value types and references

假设我们有以下 Base class,以及两个派生的 classes 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;
};

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

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

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

Base 中有一个名为 index 的纯虚函数是一种解决方案。然而,在那种情况下,我们需要在两个派生的 class 中使用相同的 int index(uint x) { return _array[x]; } 实现。这很丑陋,我们无法在 Base 中实现该功能,因为它不知道 _array.

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

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

一种可能的解决方案是使用免费功能:

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

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

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

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

使用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.