Правила наследования C++ для оператора индекса

У меня есть вопрос, касающийся оператора индекса, перегрузки и наследования в 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); }
};

Поскольку я потенциально наследую от родителя много мест, и для обслуживания плохо, когда приходится вручную указывать такие функции. Спасибо за ваши идеи.

1 ответ

Решение

Избегайте двух вещей в 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()]; 
}

Этот подход, также известный как идиома невиртуального интерфейса, представляет собой хорошее разделение проблем между клиентами базового класса и разработчиками производных классов. Это также решает проблему компиляции как побочный эффект.

Другие вопросы по тегам