Правила наследования 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()];
}
Этот подход, также известный как идиома невиртуального интерфейса, представляет собой хорошее разделение проблем между клиентами базового класса и разработчиками производных классов. Это также решает проблему компиляции как побочный эффект.