C++继承规则:下标运算符操作符重载

4

我有一个关于C++中下标运算符、重载和继承的问题。我相信,如果你有一个包含多个函数重载的父类,子类可以覆盖其中一个函数并继承其他函数。但这似乎不适用于下标运算符。(我做出了错误的假设。它与任何其他函数没有区别。)请考虑以下代码:

struct A {};
struct B {};

struct Parent
{
   virtual ~Parent() {}
   virtual int operator[](A index) { return -1; }
   virtual int operator[](B index) { return -2; }
};

struct Child : public Parent
{
   virtual int operator[](B index) override { return -3; }
};

int main()
{
   // error: no match for 'operator[]' (operand types are 'Child' and 'A')
   return Child()[A()]; 
}

我希望它使用父级的下标运算符而不是导致错误。是否可以从父级继承一些重载的下标运算符并覆盖其他运算符?如果不行,有没有比以下方法更好的解决方案:
struct Child : public Parent
{
    virtual int operator[](B index) override { return -3; }
    // Force it to use the parent method
    virtual int operator[](A index) override { return Parent::operator[](index); }
};

由于我可能从父对象继承多个位置,为了方便维护,手动指定函数是不好的。感谢您的想法。


2
总是可以使用 using Parent::operator[],但是你仍然需要在每个类中编写它。 - Weak to Enuma Elish
1
重载解析一旦找到任何具有所需名称的候选项就会停止。因此,它将看到Child::operator[](B)并停止寻找其他重载,因此它永远不会看到接受A的版本。如果像@JamesRoot建议的那样使用using Parent::operator[],它将把所有其他重载带入Child的范围内,因此重载将按预期工作。 - 0x5453
1
你为什么认为这个问题因为下标运算符而与众不同?将你的代码修改为使用一个名为 f 的普通函数,你会遇到相同的编译错误。 - Christian Hackl
@ChristianHackl,是的。我做出了错误的假设。这是所有函数的C++限制。 - Mark
@JamesRoot(和@0x5453),我喜欢那个想法。我会用的。谢谢。 - Mark
1个回答

5

在C++中要避免两件事情:

  • 混合使用重载和覆盖。
  • 公共虚函数(如果不是析构函数)。

保持基类重载运算符为非虚函数,让它们委托给具有不同名称的私有虚函数。

以下是一个例子:

struct A {};
struct B {};

struct Parent
{
   virtual ~Parent() {}
   int operator[](A index) { return withA(index); }
   int operator[](B index) { return withB(index); }
private:
   virtual int withA(A index) { return -1; }
   virtual int withB(B index) { return -2; }
};

struct Child : public Parent
{
private:
   virtual int withB(B index) override { return -3; }
};

int main()
{
   return Child()[A()]; 
}

这种方法,也被称为非虚拟接口习惯用法,在基类的客户端和派生类的实现者之间实现了很好的关注点分离。它还作为一个副作用解决了您的编译问题。

我在示例中省略了虚析构函数,以简化代码,但从技术上讲,它应该存在(我已将其添加到问题中)。这是一个有效的想法,但我会采用James Root的想法。谢谢。 - Mark

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接