Delphi vs C++ vs C#
, ну и Java немножко, где-то ближе к старшему байту номеров страниц
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
| ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
| [216.73.216.156] |
|
|
Правила раздела:
| Страницы: (495) « Первая ... 138 139 [140] 141 142 ... 494 495 ( Перейти к последнему сообщению ) |
Delphi vs C++ vs C#
, ну и Java немножко, где-то ближе к старшему байту номеров страниц
|
Сообщ.
#2086
,
|
|
|
|
Цитата korvin @ Цитата D_KEY @ Прочитал. Ты мне про гипотетический пример(на который тут уже ответили, повторятся не буду), а я тебе про реальное программирование. Приведи пример полезности интерфейсов в языке со множественным наследованием и абстрактными классами. возможность единообразно работать с разными классами, не связанными отношением наследования. вот есть у тебя несколько классов, с разными предками, но с некоторыми методами с одинаковыми сигнатурами, как ты напишешь одну функцию для работы с ними? Функции, функции... Могу завести абстрактный класс и унаследовать от него нужные классы, могу просто сделать не функцию, а шаблон функции. |
|
Сообщ.
#2087
,
|
|
|
|
Цитата D_KEY @ Функции, функции... Могу завести абстрактный класс и унаследовать от него нужные классы, могу просто сделать не функцию, а шаблон функции. можно и гланды через задний проход удалять, да... Добавлено Цитата D_KEY @ Функции, функции... Могу завести абстрактный класс и унаследовать от него нужные классы, могу просто сделать не функцию, а шаблон функции. про абстрактный клас как-то не понял, пример можно? вот есть у тебя ![]() ![]() class A { foo(), bar(), ... } class B { foo(), bar(), ... } class C { foo(), bar(), ... } как будет выглядеть абстрактный класс? |
|
Сообщ.
#2088
,
|
|
|
|
Цитата korvin @ Цитата D_KEY @ Функции, функции... Могу завести абстрактный класс и унаследовать от него нужные классы, могу просто сделать не функцию, а шаблон функции. можно и гланды через задний проход удалять, да... А в чем принципиальная разница? Интерфейсы, кстати, несколько искажают принцип ОО-декомпозиции, поскольку заставляют объявлять искуственные сущности, представляющие собой не какое-то абстрактное понятие, а просто набор нужных методов/действий. Что-то интересное на эту тему мне попадалось, возможно, что от того же Мейера... |
|
Сообщ.
#2089
,
|
|
|
|
Что-то не вижу, как эти слова коррелируют с вашими несколько странными утверждениями... Ну, я же не знал, что вы следует соглашениям .NET'а ![]() Цитата korvin @ лол, интерфейсы для того и нужны, чтоб для совершенно разных классов, но реализующих один интерфейс можно было написать одну функцию Сколько менторского пафоса то ![]() При чём тут приведение типов? ![]() Вы, похоже, не понимаете, что в моём последнем примере класс B реализует интерфейс IA два раза: как наследник класса A и самостоятельно - как часть реализации IB. Частный же случай, когда эти две реализации должны совпадать, т.е. когда реализация IA как части IB должна делегироваться классу A, был показан два раза: Повстанець'ом и мной. Теперь же я хочу увидеть на Delphi/C# решение предложенной мной задачи. Будете дальше непонятки строить или таки приведёте код? Цитата korvin @ множественное наследование тут не при чем. статический полиморфизм причем. точнее даже приведение типов Тут как раз множественное наследование... |
|
Сообщ.
#2090
,
|
|
|
|
Цитата korvin @ Цитата D_KEY @ Функции, функции... Могу завести абстрактный класс и унаследовать от него нужные классы, могу просто сделать не функцию, а шаблон функции. про абстрактный клас как-то не понял, пример можно? вот есть у тебя ![]() ![]() class A { foo(), bar(), ... } class B { foo(), bar(), ... } class C { foo(), bar(), ... } как будет выглядеть абстрактный класс? Что-то я не понял, как твой псевдокод соотносится с твоим примером про функцию. Что принимает функция? Вот и создаешь абстрактный класс для такой сушности. Какие-то классы ты можешь унаследовать от него, какие-то - нет, воспользовавшись такими паттернами, как "адаптер", "декоратор", "прокси" и др., в зависимости от потребностей. |
|
Сообщ.
#2091
,
|
|
|
|
Цитата korvin @ множественное наследование тут не при чем. статический полиморфизм причем. точнее даже приведение типов грубо говоря (точно проверить сейчас возможности нет) в Делфи это будет так: ![]() ![]() type A = class procedure f; end; B = class (A) procedure f; override; procedure g; end; procedure A.f; begin WriteLn( 'A.f' ); end; procedure B.f; begin WriteLn( 'B.f' ); end; procedure B.g; begin WriteLn( 'B.g' ); end; procedure f1 (x : A); begin x.f; end; procedure f2 (x : B); begin x.f; x.g; end; var x : B; begin x := B.Create; f1( x as A ); f2( x ); end; Добавлено Цитата D_KEY @ Что-то я не понял, как твой псевдокод соотносится с твоим примером про функцию. Что принимает функция? Вот и создаешь абстрактный класс для такой сушности. Какие-то классы ты можешь унаследовать от него, какие-то - нет, воспользовавшись такими паттернами, как "адаптер", "декоратор", "прокси" и др., в зависимости от потребностей. функция принимает объект интерфейса I, такого, что ![]() ![]() interface I { foo(), bar() } т.е. ![]() ![]() function f (x : I) { ... } |
|
Сообщ.
#2092
,
|
|
|
|
Цитата korvin @ грубо говоря (точно проверить сейчас возможности нет) в Делфи это будет так: Дык не то ведь! Функции должны принимать интерфейсы, об их конкретных реализациях они ничего не знают. Ну, может, если так переделаю, станет понятнее ![]() ![]() #include <iostream> class IA { public: virtual void f() = 0; }; class IB : public IA { public: virtual void g() = 0; }; class A : public IA { public: virtual void f() { std::cout << "A::f()" << std::endl; } }; class Base : public IB { void f() { IB_f(); } public: virtual void IB_f() = 0; }; class B : public A, public Base { public: virtual void g() { std::cout << "B::g()" << std::endl; } virtual void IB_f() { std::cout << "B::f()" << std::endl; } }; void f1(IA& iface) { iface.f(); } void f2(IB& iface) { iface.f(); iface.g(); } int main() { B b; f1(static_cast<A&>(b)); f1(static_cast<IB&>(b)); f2(b); return 0; } ![]() ![]() A::f() B::f() B::f() B::g() |
|
Сообщ.
#2093
,
|
|
|
|
Цитата korvin @ функция принимает объект интерфейса I, такого, что ![]() ![]() interface I { foo(), bar() } т.е. ![]() ![]() function f (x : I) { ... } То есть у сущности даже названия нет? Подтверждаешь мои слова насчет несоответствия принципам ОО-декомпозиции Ну так в чем проблема-то? Еще раз повторяю, что ты можешь просто написать шаблон фунции. Чем не устраивает? Можешь создать абстрактный класс, вместо интерфейса и унаследовать от него нужные классы. Можешь добавить ко второму способу автоматическое создание объекта-обертки. |
|
Сообщ.
#2094
,
|
|
|
|
Цитата D_KEY @ Что-то я не понял, как твой псевдокод соотносится с твоим примером про функцию. Что принимает функция? Вот и создаешь абстрактный класс для такой сушности. Какие-то классы ты можешь унаследовать от него, какие-то - нет, воспользовавшись такими паттернами, как "адаптер", "декоратор", "прокси" и др., в зависимости от потребностей. , ох, еще кучу кода городить для реализации паттернов? нет уж, увольте. вот пример на Go (только там нет наследования, но просто считай, что A, B, C -- некие классы без общих предков): ![]() ![]() type A struct { // ... } func (a A) foo() { // ... } func (a A) bar() { // ... } //-------------- type B struct { // ... } func (b B) foo() { // ... } func (b B) bar() { // ... } //-------------- type C struct { // ... } func (c C) foo() { // ... } func (c C) bar() { // ... } тогда я делаю так: ![]() ![]() type I interface { foo() bar() } func f(x I) { x.foo() x.bar() } и все... Добавлено Цитата MyNameIsIgor @ Дык не то ведь! Функции должны принимать интерфейсы, об их конкретных реализациях они ничего не знают. Ну, может, если так переделаю, станет понятнее тю, да я просто забыл, что f1 и f2 у тебя классами IA и IB типизируются. ну так это опять же ничего не меняет, у тебя по сути просто перекрытие метода предка. ну добавлю я интерфейсы: ![]() ![]() type IA = interface procedure f; end; IB = interface (IA) procedure g; end; A = class (IA) procedure f; end; B = class (A, IB) procedure f; override; procedure g; end; procedure A.f; begin WriteLn( 'A.f' ); end; procedure B.f; begin WriteLn( 'B.f' ); end; procedure B.g; begin WriteLn( 'B.g' ); end; procedure f1 (x : IA); begin x.f; end; procedure f2 (x : IB); begin x.f; x.g; end; var x : B; begin x := B.Create; f1( x as A ); f2( x ); end; как-то так Добавлено Цитата D_KEY @ То есть у сущности даже названия нет? Подтверждаешь мои слова насчет несоответствия принципам ОО-декомпозиции ![]() 1. у какой сущности нет названия? 2. анонимные классы уже не в моде? а вот в SICP пишут, что создание сущности и ее именование -- совершенно ортогональные операции =) |
|
Сообщ.
#2095
,
|
|
|
|
Цитата korvin @ тю, да я просто забыл, что f1 и f2 у тебя классами IA и IB типизируются. ну так это опять же ничего не меняет, у тебя по сути просто перекрытие метода предка. ну добавлю я интерфейсы: Ну, и теперь ещё в f1 запихать B, чтобы вывод с моим совпал |
|
Сообщ.
#2096
,
|
|
|
|
Цитата MyNameIsIgor @ Цитата korvin @ тю, да я просто забыл, что f1 и f2 у тебя классами IA и IB типизируются. ну так это опять же ничего не меняет, у тебя по сути просто перекрытие метода предка. ну добавлю я интерфейсы: Ну, и теперь ещё в f1 запихать B, чтобы вывод с моим совпал ![]() ![]() ![]() f1(x); Добавлено Цитата D_KEY @ 1) Еще раз повторяю, что ты можешь просто написать шаблон фунции. Чем не устраивает? 2) Можешь создать абстрактный класс, вместо интерфейса и унаследовать от него нужные классы. 3) Можешь добавить ко второму способу автоматическое создание объекта-обертки. 1) и получаем в итоге то, что видели на картинке =) кстати шаблоны же на каждый тип, к которому применяются, создают отдельную функцию? вроде раньше по крайней мере было, что они генерировали кучу классов; 2) как будет выглядеть этот класс и какие классы я от него буду наследовать? 3) и как будет выглядеть описание класса этого объекта-обертки? |
|
Сообщ.
#2097
,
|
|
|
|
Цитата korvin @ , ох, еще кучу кода городить для реализации паттернов? нет уж, увольте. Сразу видно понимающего в паттернах человека. Не надо их городить, если они тебе не нужны. Цитата вот пример на Go (только там нет наследования, но просто считай, что A, B, C -- некие классы без общих предков): ![]() ![]() type A struct { // ... } func (a A) foo() { // ... } func (a A) bar() { // ... } //-------------- type B struct { // ... } func (b B) foo() { // ... } func (b B) bar() { // ... } //-------------- type C struct { // ... } func (c C) foo() { // ... } func (c C) bar() { // ... } тогда я делаю так: ![]() ![]() type I interface { foo() bar() } func f(x I) { x.foo() x.bar() } и все... Так ты ответишь, чем тебе не нравится: ![]() ![]() template<typename T> void f(T x) { x.foo(); x.bar(); } ? Цитата Цитата D_KEY @ То есть у сущности даже названия нет? Подтверждаешь мои слова насчет несоответствия принципам ОО-декомпозиции ![]() 1. у какой сущности нет названия? 2. анонимные классы уже не в моде? а вот в SICP пишут, что создание сущности и ее именование -- совершенно ортогональные операции =) 1. У той, "тип" которой ты описываешь своим интерфейсом 2. Ты не понял о чем я Дело не в том, чтобы задать сущности явное имя, дело в создании лишней сущности тогда, когда она не нужна. |
|
Сообщ.
#2098
,
|
|
|
|
шаблоны тут как раз в некотором роде заменяют интерфейсы
Добавлено Цитата D_KEY @ Сразу видно понимающего в паттернах человека. Не надо их городить, если они тебе не нужны. прям откровение =) мне -- не нужны, ты же предлагал ими воспользоваться |
|
Сообщ.
#2099
,
|
|
|
|
Цитата korvin @ шаблоны тут как раз в некотором роде заменяют интерфейсы Кто кого заменяет - это еще вопрос. Интерфейс явно вводит новый "тип" и требует, чтобы аргумент ему соответствовал. Не очень-то соответствует "утиной типизации" которая нам тут, фактически, нужна. Шаблон же говрит, что тип может быть любым, но требуется, что вот такие-то операции можно осуществить с объектами этого типа. Добавлено Цитата korvin @ ты же предлагал ими воспользоваться Когда потребуется |
|
Сообщ.
#2100
,
|
|
|
|
Цитата D_KEY @ Так ты ответишь, чем тебе не нравится: ![]() ![]() template<typename T> void f(T x) { x.foo(); x.bar(); } ? тем, что шаблон никак не может проверить, реализует ли переданный ему тип нужный интерфейс (методы foo и bar), потому и получаем ошибки уже после раскрытия шаблона в кучу кода. или таки может? |