Наследование класса, который также наследует тот же базовый класс, что и этот класс

Одним из преимуществ наследования для меня является то, что общедоступные методы записываются один раз в базовом классе, и каждый наследующий класс также автоматически имеет этот метод.

Теперь, например, скажем, я хочу предоставить каждому классу в моем программном обеспечении метод «своп». Класс, обеспечивающий эту функциональность, выглядит так:

template< typename... DataMembers > 
class SwapMethodProvider
{
public:

    inline void Swap( SwapMethodProvider& other );

private:

    std::tuple< DataMembers... > member_dataMembers;

};

template< typename... DataMembers >
inline void SwapMethodProvider< DataMembers... >::Swap( SwapMethodProvider& other )
{
    // Swap between the tuples that contain the data members
    std::swap( member_dataMembers, other.member_dataMembers );
}

Теперь, если только один класс наследуется от этого, все хорошо. Но если я хочу, чтобы каждый класс в моем программном обеспечении наследовался от этого, то следующее не будет работать, потому что прямой базовый класс недоступен из-за неоднозначности:

class ExtraSauce : public SwapMethodProvider< int, double >
{};

class EvenMoreExtraSauce : public ExtraSauce, public SwapMethodProvider< int, double >
{};

Тогда первый класс «ExtraSauce» будет работать нормально, но «EvenMoreExtraSauce» не будет компилироваться. Теперь я понимаю, почему он не компилируется, но осталось сохранить экземпляр класса SwapMethodProvider в качестве члена данных. Моя проблема заключается только в повторяющемся коде, потому что каждый класс должен иметь свой собственный метод «Swap», который вызывает метод «Swap» экземпляра «SwapMethodProvider».

Во-первых, прав ли я до сих пор? Я хотел бы знать наверняка, что такое поведение невозможно.

Во-вторых, почему наследование так плохо поддерживается за одним уровнем? Так здорово один раз написать метод, а затем позволить всем объектам наследоваться от него. Даже если один и тот же объект появляется в классе более одного раза по-разному.

на самом деле это не так, что наследование плохо поддерживается, но само наследование в какой-то момент становится неприятным. Учтите, что наследование не является святым Граалем, и, возможно, взгляните на std::swap, на самом деле для замены произвольных типов наследование вообще не требуется.

463035818_is_not_a_number 09.04.2019 15:21

Предполагая, что он компилируется. Когда вы вызываете Swap на своем EvenMoreExtraSauce, какое поведение вы ожидаете?

user1531591 09.04.2019 15:23

Что-то вроде поведения конструктора, что может быть специальный метод, который вызывает один и тот же метод для всех базовых классов

rrrrTTTrrrr 09.04.2019 15:27
Он отлично компилируется. Опубликуйте минимальный воспроизводимый пример.
n. 1.8e9-where's-my-share m. 09.04.2019 15:34

Если вы не определили метод Swap в своем EvenMoreExtraSauce, который вызывает ExtraSauce::Swap, то/или SwapMethodProvider< std::string >::Swap. Как компилятор должен анализировать EvenMoreExtraSauce ::Swap ? это ExtraSauce::Swap или SwapMethodProvider<std::string>::Swap. В конструкторе по умолчанию он вызывает конструктор по умолчанию для каждого класса, но для метода он не может выбрать произвольный вариант.

user1531591 09.04.2019 15:41

Извините, у 2 «SwapMethodProvider» были разные аргументы шаблона, поэтому они были разными классами. Я починил это. Поскольку «EvenMoreExtraSauce» наследуется от всех, все методы подкачки базового класса можно просто вызывать с помощью указателя «this». То, что вы сказали, правильно

rrrrTTTrrrr 09.04.2019 15:46
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
6
60
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

CRTP.

template <class Parent, typename... DataMembers> 
class SwapMethodProvider { ... };
class ExtraSauce : public SwapMethodProvider <ExtraSauce, int, double> {};
class EvenMoreExtraSauce : public ExtraSauce, 
                           public SwapMethodProvider<EvenMoreExtraSauce, int, double> {};

Большое спасибо!! Было весело проходить это с некоторой помощью

rrrrTTTrrrr 09.04.2019 18:08

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