Как правильно выразить две функции производного класса с одинаковой реализацией в C ++? - PullRequest
7 голосов
/ 07 июня 2019

В настоящее время я нахожусь в ситуации, когда у меня есть некоторый базовый класс и много подклассов.Подклассы должны переопределять несколько виртуальных методов, однако иногда реализация виртуального метода в одном подклассе точно идентична другому подклассу.Должен ли я просто скопировать и вставить код реализации в другой подкласс или есть способ выразить реализацию для обоих подклассов одновременно?

Код ниже демонстрирует мою проблему.

class A
{
    virtual void foo1() = 0;
    virtual void foo2() = 0;
};

class B : public A
{
    void foo1();
    void foo2();
};

class C : public A
{
    void foo1();
    void foo2();
};

class D : public A
{
    void foo1();
    void foo2();
};

void B::foo1()
{
     // Same implementation of foo1 as C
}

void C::foo1()
{
     // Same implementation of foo1 as B
}

void D::foo1()
{
     // Different implementation of foo1
}

void B::foo2()
{
     // Different implementation of foo2
}

void C::foo2()
{
     // Different implementation of foo2
}

void D::foo2()
{
     // Different implementation of foo2
}

Могу ли я как-то объединить реализацию для B и C?

Примечание: я явно выписал foo2, потому что в противном случае подклассы B и C были бы идентичны во всех отношениях.

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

Ответы [ 2 ]

12 голосов
/ 07 июня 2019

Добавьте промежуточный прокси-класс:

class BC : public A {
    void foo1();
};

class B : public BC {
    void foo2();
};

class C : public BC {
    void foo2();
};

Как уже упоминалось @Fureeish - не повторяйте себя.

Что делать, если количество классов / функций огромно:

Сделайте то же самое.В худшем случае вы закончите (примерно) тем же количеством кода, с большим количеством классов, но с меньшим количеством функций.Даже тогда это чистая победа, потому что вы удалили много избыточности кода, и хотя структура наследования хуже, качество кода намного лучше.На практике такая плотная «матрица столкновений» предполагает, что что-то не так с самими классами.Может быть, те промежуточные классы, которые вы создали, должны быть написаны в первую очередь?Во всех случаях сокращение избыточности кода - большая победа.

4 голосов
/ 07 июня 2019

вижу два варианта:

  • Переместите общий код в некоторый интерфейс (возможно, частный) и просто вызовите этот интерфейс внутри двух ваших функций.

  • Предоставьте реализацию по умолчанию и просто не переопределяйте ее, т. Е. Вместо создания foo1 чисто виртуальной, просто реализуйте поведение по умолчанию там.

Очевидно, что по умолчанию не существует способа сделать то, что должен foo1 сделать. Тогда я предлагаю придерживаться первого варианта.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...