Агрегирование
От: s.ts  
Дата: 30.01.08 20:11
Оценка:
Привет всем.

В предыдущем посте ошибка, потому заново.

Есть такой код:


struct iface
{
  virtual void method1() =0;
...
  virtual void method50() =0;
  virtual ~iface(){}
};

class ext: public iface
{
  iface* ptr;

public:
  explicit ext(iface* a_ptr): ptr(a_ptr) {}
  void method1() {ptr->method1();};
...
  void method50() {ptr->method50();};
};

iface* convert(iface* impl)
{
  return new ext(impl);
}




Т.е. имеется интерфейс 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; }
или что-то типа того.
Re: Агрегирование
От: Анатолий Широков СССР  
Дата: 30.01.08 22:23
Оценка:
ST>Есть такой код:
...

ST>Вопрос.

ST>Можно ли как-нибудь изменить этот код так, чтобы не пришлось во 2-й раз перечислять виртуальные методы iface в классе ext?

Лучше не будет, чем есть сейчас, поскольку существующих код легко поддерживать и валидировать, все остальное будет выглядеть монстрообразно и только запутает.
Re[2]: Агрегирование
От: s.ts  
Дата: 31.01.08 05:41
Оценка:
Здравствуйте, Аноним, Вы писали:

ST>>Вопрос.

ST>>Можно ли как-нибудь изменить этот код так, чтобы не пришлось во 2-й раз перечислять виртуальные методы iface в классе ext?
А>нет. можешь маленькую прогу сделать которая за тебя будет подобный код генерить, если саму лень переписывать методы или их много.

А>лучше пользуй хитрые указатели сделай оператор "operator -> ()" виртуальным и занимайся развратом :P

А>virtual iface* operator -> () { return something()?ptr1:ptr2; }
А>или что-то типа того.

Так не получится или я что-то не понял ?
Re[2]: Агрегирование
От: s.ts  
Дата: 31.01.08 05:52
Оценка:
Здравствуйте, Анатолий Широков, Вы писали:

ST>>Вопрос.

ST>>Можно ли как-нибудь изменить этот код так, чтобы не пришлось во 2-й раз перечислять виртуальные методы iface в классе ext?

АШ>Лучше не будет, чем есть сейчас, поскольку существующих код легко поддерживать и валидировать, все остальное будет выглядеть монстрообразно и только запутает.


Ну, можно выделить инструмент отдельно.
Его работу понимать не обязательно для поддержки.
Зато портянки кода исчезнут.

Как пример решения которое не устраивает:
class iface
{
  iface* ptr;

public:
  explicit ext(iface* a_ptr = 0): ptr(a_ptr) {}

  virtual void method1() {assert(ptr);ptr->method1();};
...
  virtual void method50() {assert(ptr);ptr->method50();};
  virtual ~iface(){}
};

class ext: public iface
{
public:
  explicit ext(iface* a_ptr): iface(a_ptr) {}
};

iface* convert(iface* impl)
{
  return new ext(impl);
}

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

Во многих языках есть синтаксический сахар, позволяющий делегировать реализацию интерфейсов агрегированному объекту.
Придумать бы нечто подобное для с++.
Re[3]: Агрегирование
От: Анатолий Широков СССР  
Дата: 31.01.08 08:05
Оценка:
Здравствуйте, 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() {...}
*/
};


Вообщем, лучше, чем у вас есть сейчас, думаю, ничего не придумать — все под контролем компилятора — чего еще желать?
Re[4]: Агрегирование
От: s.ts  
Дата: 31.01.08 08:42
Оценка:
Здравствуйте, Анатолий Широков, Вы писали:

ST>>Как пример решения которое не устраивает:

АШ>[...]
ST>>Кода становится меньше.
ST>>Но при этом проверка на "забыл переопределить абстрактный метод" переезжает из компайл-тайма в рантайм.

АШ>Такой подход ничего не даст — он упрощает код агрегата (хотя его-то как раз надо написать один раз и все), но вы будете вынуждены переопределять все виртуальные функции для всех прямых конкретных потомков класса iface, чтобы банально избежать бесконечной рекурсии при вызове виртуальных функций и каждый раз должны будете помнить о том — все ли методы вы определили — это кошмар для тех, кто будет поддерживать вашу иерархию:


Виртуальные функции и так надо переопределять. Никуда не денешься.
Тут выполнены почти все условия. Код непосредственных потомков не меняется.
По поводу контроля уже говорил:

ST>>Но при этом проверка на "забыл переопределить абстрактный метод" переезжает из компайл-тайма в рантайм.

Это главный недостаток. Потому такой подход и не принимается

АШ>
АШ>class concrete: public iface
АШ>{
АШ>public:
АШ>  explicit concrete(): iface(this) {}
АШ>/* если не переопределить все виртуальные функции - то вызов любой виртуальной функции приведет к бесконечной рекурсии
АШ>  void method1() {...}
АШ>  void method50() {...}
АШ>*/
АШ>};
АШ>


Ну, это-то не проблема. Втыкнуть еще на дурака assert(ptr != this). Сути это ИМХО не меняет.

АШ>Вообщем, лучше, чем у вас есть сейчас, думаю, ничего не придумать — все под контролем компилятора — чего еще желать?


Но можно попробовать
Какую-нибудь кодогенерацию на шаблонах/макросах
Re[5]: Агрегирование
От: Анатолий Широков СССР  
Дата: 31.01.08 08:52
Оценка:
ST>Ну, это-то не проблема. Втыкнуть еще на дурака assert(ptr != this). Сути это ИМХО не меняет.

И тогда ваш асерт будет валится для агрегата.

АШ>>Вообщем, лучше, чем у вас есть сейчас, думаю, ничего не придумать — все под контролем компилятора — чего еще желать?


ST>Но можно попробовать

ST>Какую-нибудь кодогенерацию на шаблонах/макросах

"А вот это попробуйте" (с) Брильянтовая рука

Всего-то:
1) создать тул который будет собирать мета информацию о классе
2) сгенерировать тела методов агрегата
3) втроится в существующую систему билда
и дело в шляпе...
Re[6]: Агрегирование
От: s.ts  
Дата: 31.01.08 09:33
Оценка:
Здравствуйте, Анатолий Широков, Вы писали:


ST>>Ну, это-то не проблема. Втыкнуть еще на дурака assert(ptr != this). Сути это ИМХО не меняет.


АШ>И тогда ваш асерт будет валится для агрегата.


У объекта, который непосредственно наследуется от iface ptr == 0
У агрегирующего ptr != this && ptr != 0
Или я чего-то не понимаю.
Если можно, пример валящегося кода.
Я подразумевал assert в следующем месте:
struct iface
{
...
  virtual void methodN(){assert(ptr && ptr != this); ptr->methodN();}
...
};


АШ>>>Вообщем, лучше, чем у вас есть сейчас, думаю, ничего не придумать — все под контролем компилятора — чего еще желать?


ST>>Но можно попробовать

ST>>Какую-нибудь кодогенерацию на шаблонах/макросах

АШ>"А вот это попробуйте" (с) Брильянтовая рука


АШ>Всего-то:

АШ>1) создать тул который будет собирать мета информацию о классе
АШ>2) сгенерировать тела методов агрегата
АШ>3) втроится в существующую систему билда
АШ>и дело в шляпе...

Не обязательно собирать, генерировать и встраиваться .
Если бы речь была о статическом полиморфизме и шаблонных функциях, то можно было бы, например, попробовать SFINAE и что-нибудь типа boost::enable_if. Разрешать в зависимости от доп. шаблонного параметра или запрещать нужную реализацию.
Re[7]: Агрегирование
От: Анатолий Широков СССР  
Дата: 31.01.08 10:00
Оценка:
Здравствуйте, s.ts, Вы писали:

ST>Здравствуйте, Анатолий Широков, Вы писали:



ST>>>Ну, это-то не проблема. Втыкнуть еще на дурака assert(ptr != this). Сути это ИМХО не меняет.


АШ>>И тогда ваш асерт будет валится для агрегата.


ST>У объекта, который непосредственно наследуется от iface ptr == 0

ST>У агрегирующего ptr != this && ptr != 0

Ok.

ST>Не обязательно собирать, генерировать и встраиваться .

ST>Если бы речь была о статическом полиморфизме и шаблонных функциях, то можно было бы, например, попробовать SFINAE и что-нибудь типа boost::enable_if. Разрешать в зависимости от доп. шаблонного параметра или запрещать нужную реализацию.

Я высказал свое мнение, если вы хотите развивать эту идею, то я вас, ни в коем случае, не сдерживаю.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.