Хорошо ли реализовать миксин шаблон с помощью макроса #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 в вашем коде).
это вызовет трения в вашей команде в будущем; по крайней мере, если в вашей команде есть разработчики, которые заботятся о качестве и простоте использования вашего кода.