CSerial; //базовая работа с COM портом и все константы
CSerialEx : CSerial; //мониторит порт в отдельном потоке
Потом копипастом добавилось еще два, отличающиеся только одной вложенной структурой (внутри базового) и вызывающие другой API (D2XX вместо виртуального COM порта, отличается грубо говоря префиксом в именах функций и использованием той самой структуры)
CFTSerial; //базовая работа с COM портом через D2XX и все константы
CFTSerialEx : CFTSerial; //мониторит порт в отдельном потоке
Вопрос, как организовать это и минимизировать копипаст?
добавилось еще два, отличающиеся только одной вложенной структурой (внутри базового) и вызывающие другой API (D2XX вместо виртуального COM порта, отличается грубо говоря префиксом в именах функций и использованием той самой структуры)
Ну окромя шаблонов, макросов и if-ов есть вариант ввести ещё один уровень наследования, вынеся в «промежуточный» класс максимум копипасты. Не факт, что это лучшее решение, вполне возможно, что с шаблонами будет изящнее и прозрачнее.
А ещё меня терзает смутное подозрение, что у первых двух классов (судя по комментариям к их объявлению) вероятно, должно было быть не наследование, а включение. Т.е. в потомке у тебя получается не разновидность предка, а класс, который «делает, что-то ещё», опираясь на методы предка.
Если моя догадка верна, то вполне возможно, что вместо CSerialEx и CFTSerialEx можно сделать один класс, а вот в качестве низкоуровневой прослойки ему можно передавать абстрактный класс работы с портом, у которого есть два потомка-реализации. Классов по-прежнему 4, но копипасты в них будет минимум
Собственно говоря, это очень похоже на диаграмму классов в вики-статье про паттерн «Стратегия» :) Да по сути, это она и есть... Хотя вру, для классической «стратегии» из статьи классов понадобится уже 5.
Хотя если CSerialEx и CFTSerialEx в низкоуровневой части не полностью полагаются на предков, а добавляют ещё какие-то вызовы API, это не спасёт.
Тоды ой. Но тогда и разделение между базовым классом и потомком выглядит искусственным.
Может, всё-таки подумать над тем, нельзя ли сделать так, чтобы всё API ушло в один класс? Если класс очень большой - это не проблема, проблема, когда его границы очерчены неправильно...
Ман композиция. Какого фига вообще «мониторит порт в отдельном потоке» унаследовано от «базовая работа с COM портом и все константы»? Сделай несколько специализаций от абстрактного CSerial, а в CSerialEx передавай инстанцию одной из них.
да, я поддержу вариант с выносом API по работе с разными интерфейсами (D2XX и Virtual COM) в отдельные классы, которые будут унаследованы от абстрактного класса, представляющего девайс с необходимыми интерфейсами.
а в классы-обработчики передавать инстанс нужной реализации. можно это сделать в фабрике.
P.S. раньше много писали подобных утилек для работы с FTDI чипами, именно так и делали.
компилятор проверяет много вещей в темплейтах. и там при желании можно сделать много проверок. а в макросах он ничего не проверяет, просто подставляет текст.
Ты споришь с лиспером, а они любят приравнивать эти вещи. Хотя темплейты, сишные макросы и «нормальные макросы» - три разные сущности, хотя и могут делать похожие вещи.