Т.е. имеется интерфейс iface.
Мы получаем (в функции convert) объект, который некоторым образом этот интерфейс реализовывает.
Cлегка изменяем его поведение, используя агрегирование.
При этом приходится тривиальным образом переопределять методы iface в классе ext просто как вызовы агрегированного объекта.
Вопрос.
Можно ли как-нибудь изменить этот код так, чтобы не пришлось во 2-й раз перечислять виртуальные методы iface в классе ext?
При этом.
Методы интерфейса iface могут иметь различное число параметров и типы возвращаемых значений.Мы можем изменять iface, но при этом должны сохраниться все существующие свойства кода, как, например, проверка попыток инстанцирования абстрактных классов, динамический полиморфизм и т.д.
Re: Агрегирование
От:
Аноним
Дата:
30.01.08 21:55
Оценка:
Здравствуйте, s.ts, Вы писали:
ST>Есть такой код: ST>[ccode] ST>struct iface ST>{ ST> virtual void method1() =0; ST>... ST> virtual void method50() =0; ST>};
...
ST>Вопрос. ST>Можно ли как-нибудь изменить этот код так, чтобы не пришлось во 2-й раз перечислять виртуальные методы iface в классе ext?
нет. можешь маленькую прогу сделать которая за тебя будет подобный код генерить, если саму лень переписывать методы или их много.
лучше пользуй хитрые указатели сделай оператор "operator -> ()" виртуальным и занимайся развратом :P
virtual iface* operator -> () { return something()?ptr1:ptr2; }
или что-то типа того.
ST>Есть такой код:
...
ST>Вопрос. ST>Можно ли как-нибудь изменить этот код так, чтобы не пришлось во 2-й раз перечислять виртуальные методы iface в классе ext?
Лучше не будет, чем есть сейчас, поскольку существующих код легко поддерживать и валидировать, все остальное будет выглядеть монстрообразно и только запутает.
Здравствуйте, Аноним, Вы писали:
ST>>Вопрос. ST>>Можно ли как-нибудь изменить этот код так, чтобы не пришлось во 2-й раз перечислять виртуальные методы iface в классе ext? А>нет. можешь маленькую прогу сделать которая за тебя будет подобный код генерить, если саму лень переписывать методы или их много.
А>лучше пользуй хитрые указатели сделай оператор "operator -> ()" виртуальным и занимайся развратом :P А>virtual iface* operator -> () { return something()?ptr1:ptr2; } А>или что-то типа того.
Здравствуйте, Анатолий Широков, Вы писали:
ST>>Вопрос. ST>>Можно ли как-нибудь изменить этот код так, чтобы не пришлось во 2-й раз перечислять виртуальные методы iface в классе ext?
АШ>Лучше не будет, чем есть сейчас, поскольку существующих код легко поддерживать и валидировать, все остальное будет выглядеть монстрообразно и только запутает.
Ну, можно выделить инструмент отдельно.
Его работу понимать не обязательно для поддержки.
Зато портянки кода исчезнут.
Кода становится меньше.
Но при этом проверка на "забыл переопределить абстрактный метод" переезжает из компайл-тайма в рантайм.
Во многих языках есть синтаксический сахар, позволяющий делегировать реализацию интерфейсов агрегированному объекту.
Придумать бы нечто подобное для с++.
Здравствуйте, s.ts, Вы писали:
ST>Здравствуйте, Анатолий Широков, Вы писали:
ST>>>Вопрос. ST>>>Можно ли как-нибудь изменить этот код так, чтобы не пришлось во 2-й раз перечислять виртуальные методы iface в классе ext?
АШ>>Лучше не будет, чем есть сейчас, поскольку существующих код легко поддерживать и валидировать, все остальное будет выглядеть монстрообразно и только запутает.
ST>Ну, можно выделить инструмент отдельно. ST>Его работу понимать не обязательно для поддержки. ST>Зато портянки кода исчезнут.
ST>Как пример решения которое не устраивает:
[...] ST>Кода становится меньше. ST>Но при этом проверка на "забыл переопределить абстрактный метод" переезжает из компайл-тайма в рантайм.
Такой подход ничего не даст — он упрощает код агрегата (хотя его-то как раз надо написать один раз и все), но вы будете вынуждены переопределять все виртуальные функции для всех прямых конкретных потомков класса iface, чтобы банально избежать бесконечной рекурсии при вызове виртуальных функций и каждый раз должны будете помнить о том — все ли методы вы определили — это кошмар для тех, кто будет поддерживать вашу иерархию:
class concrete: public iface
{
public:
explicit concrete(): iface(this) {}
/* если не переопределить все виртуальные функции - то вызов любой виртуальной функции приведет к бесконечной рекурсии
void method1() {...}
void method50() {...}
*/
};
Вообщем, лучше, чем у вас есть сейчас, думаю, ничего не придумать — все под контролем компилятора — чего еще желать?
Здравствуйте, Анатолий Широков, Вы писали:
ST>>Как пример решения которое не устраивает: АШ>[...] ST>>Кода становится меньше. ST>>Но при этом проверка на "забыл переопределить абстрактный метод" переезжает из компайл-тайма в рантайм.
АШ>Такой подход ничего не даст — он упрощает код агрегата (хотя его-то как раз надо написать один раз и все), но вы будете вынуждены переопределять все виртуальные функции для всех прямых конкретных потомков класса iface, чтобы банально избежать бесконечной рекурсии при вызове виртуальных функций и каждый раз должны будете помнить о том — все ли методы вы определили — это кошмар для тех, кто будет поддерживать вашу иерархию:
Виртуальные функции и так надо переопределять. Никуда не денешься.
Тут выполнены почти все условия. Код непосредственных потомков не меняется.
По поводу контроля уже говорил:
ST>>Но при этом проверка на "забыл переопределить абстрактный метод" переезжает из компайл-тайма в рантайм.
Это главный недостаток. Потому такой подход и не принимается
АШ>
АШ>class concrete: public iface
АШ>{
АШ>public:
АШ> explicit concrete(): iface(this) {}
АШ>/* если не переопределить все виртуальные функции - то вызов любой виртуальной функции приведет к бесконечной рекурсии
АШ> void method1() {...}
АШ> void method50() {...}
АШ>*/
АШ>};
АШ>
Ну, это-то не проблема. Втыкнуть еще на дурака assert(ptr != this). Сути это ИМХО не меняет.
АШ>Вообщем, лучше, чем у вас есть сейчас, думаю, ничего не придумать — все под контролем компилятора — чего еще желать?
Но можно попробовать
Какую-нибудь кодогенерацию на шаблонах/макросах
ST>Ну, это-то не проблема. Втыкнуть еще на дурака assert(ptr != this). Сути это ИМХО не меняет.
И тогда ваш асерт будет валится для агрегата.
АШ>>Вообщем, лучше, чем у вас есть сейчас, думаю, ничего не придумать — все под контролем компилятора — чего еще желать?
ST>Но можно попробовать ST>Какую-нибудь кодогенерацию на шаблонах/макросах
"А вот это попробуйте" (с) Брильянтовая рука
Всего-то:
1) создать тул который будет собирать мета информацию о классе
2) сгенерировать тела методов агрегата
3) втроится в существующую систему билда
и дело в шляпе...
ST>>Ну, это-то не проблема. Втыкнуть еще на дурака assert(ptr != this). Сути это ИМХО не меняет.
АШ>И тогда ваш асерт будет валится для агрегата.
У объекта, который непосредственно наследуется от iface ptr == 0
У агрегирующего ptr != this && ptr != 0
Или я чего-то не понимаю.
Если можно, пример валящегося кода.
Я подразумевал assert в следующем месте:
АШ>>>Вообщем, лучше, чем у вас есть сейчас, думаю, ничего не придумать — все под контролем компилятора — чего еще желать?
ST>>Но можно попробовать ST>>Какую-нибудь кодогенерацию на шаблонах/макросах
АШ>"А вот это попробуйте" (с) Брильянтовая рука
АШ>Всего-то: АШ>1) создать тул который будет собирать мета информацию о классе АШ>2) сгенерировать тела методов агрегата АШ>3) втроится в существующую систему билда АШ>и дело в шляпе...
Не обязательно собирать, генерировать и встраиваться .
Если бы речь была о статическом полиморфизме и шаблонных функциях, то можно было бы, например, попробовать SFINAE и что-нибудь типа boost::enable_if. Разрешать в зависимости от доп. шаблонного параметра или запрещать нужную реализацию.
Здравствуйте, s.ts, Вы писали:
ST>Здравствуйте, Анатолий Широков, Вы писали:
ST>>>Ну, это-то не проблема. Втыкнуть еще на дурака assert(ptr != this). Сути это ИМХО не меняет.
АШ>>И тогда ваш асерт будет валится для агрегата.
ST>У объекта, который непосредственно наследуется от iface ptr == 0 ST>У агрегирующего ptr != this && ptr != 0
Ok.
ST>Не обязательно собирать, генерировать и встраиваться . ST>Если бы речь была о статическом полиморфизме и шаблонных функциях, то можно было бы, например, попробовать SFINAE и что-нибудь типа boost::enable_if. Разрешать в зависимости от доп. шаблонного параметра или запрещать нужную реализацию.
Я высказал свое мнение, если вы хотите развивать эту идею, то я вас, ни в коем случае, не сдерживаю.