Хорошо ли реализовать миксин шаблон с помощью макроса #include в C++

Как мы знаем, mixin - это шаблон проектирования, который "вставляет" некоторые поведения в другой класс. Например, в Ruby мы можем написать такой код

module Flyable
  def fly
    puts "I'm flying";
  end
end

class Bird
  include Flyable
end

В C++ нет поддержки смешивания на уровне языка, но мы можем использовать множественное наследование для вставки кода в производный класс. Но у этого решения все еще есть свои проблемы, как наследование алмазов, невозможно переопределить виртуальный метод в интерфейсе, невозможно получить доступ к элементам из "родственных" модулей и т. д.

Позже я обнаружил, что могу использовать макрос #include для вставки сегмента кода в определение класса для достижения смешивания:

// in Flyable.h
public:
void fly() {
    // do something ...
}
float flySpeed;

И в другом файле

// in Bird.h
class Bird {
#include "Flyable.h"
};

Таким образом, все переменные-члены и функции вставляются в класс Bird.

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

Но все же я боюсь, что есть некоторые проблемы, которые я еще не видел. Есть ли проблемы для этого вида миксина?


редактировать

Я знаю, что использование #include внутри определения класса странно. Но это решит проблему. И программисты могут привыкнуть к этому, если он действительно используется в проекте. Итак, я хочу знать, есть ли практическая причина, по которой мы должны избегать такого кода? Не только это уродливо или странно, либо никто так не пишет.


редактировать

Я забыл объяснить цель кода. Вкратце, это решение проблемы алмазов без виртуального наследования. Насколько я понимаю, коренной причиной проблемы с бриллиантами является злоупотребление ООП. "Птица"- это "FlyableAnimal, FlyableAnimal"- это "Животное, Птица"- это "Плотоядное животное, Плотоядное животное"- это "Животное. Реальное намерение такого рода злоупотреблений - повторное использование кода, поэтому вместо отношений "есть" есть "лучше". И миксин может принести "-белые" отношения.

В C++ mixin может быть достигнуто множественным наследованием. Это довольно хорошо, но это отключит полиморфизм. Например, у нас есть интерфейс Animal с чисто виртуальными функциями, и мы хотим, чтобы Bird реализовал их. Тогда мы не можем использовать множественное наследование для внедрения реализации в класс Bird. Есть и другие методы для достижения этой цели, например, композиция. Но я не видел такого простого решения, как настоящий миксин. Вот почему я подумал о #include для mixin.

1 ответ

Это решение, похоже, не имеет очевидного недостатка.

Недостатки:

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

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

Коды хорошо организованы в разные файлы.

Вся отрасль применяет следующие соглашения для организации кода:

  • все в домене, в одном API (независимо от того, означает ли это один класс или одну коллекцию свободных функций) и обычно не более двух файлов: один для объявлений, другой для определений.

  • там, где это возможно, хранить только заголовки

  • там, где это невозможно, напишите реализацию в классе.impl или _impl и включите ее в заголовок (это не является стандартом де-факто, но вы видите, что оно используется с шаблонным кодом).

Ваше решение явно отличается от этого (то есть явно плохо организовано в разные файлы).

Возможных конфликтов имен можно избежать с помощью тщательно разработанных модулей без наложения функций / правил.

Когда люди делают это различие ("да, код можно обслуживать, нужно просто проявлять особую осторожность"), они думают, что вы смотрите на проблему, применяете решение, фиксируете, и проблема решается.

Части, которые вы склонны забывать при этом:

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

Но все же я боюсь, что есть некоторые проблемы, которые я еще не видел. Есть ли проблемы для этого вида миксина?

Подводя итог (tldr):

  • Вы будете постоянно увеличивать затраты на обслуживание в течение всего проекта.

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

  • все разработчики, которые следуют своей интуиции / полученному опыту, ожидают увидеть что-то еще в вашем проекте (увеличение WTF/sloc в вашем коде).

  • это вызовет трения в вашей команде в будущем; по крайней мере, если в вашей команде есть разработчики, которые заботятся о качестве и простоте использования вашего кода.

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