Как вы относитесь к паскалю?
, (есть гипотеза)
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
| ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
| [216.73.216.156] |
|
|
| Страницы: (20) « Первая ... 11 12 [13] 14 15 ... 19 20 все ( Перейти к последнему сообщению ) |
Как вы относитесь к паскалю?
, (есть гипотеза)
|
Сообщ.
#181
,
|
|
|
|
Линеаризация линеаризацией, но как бы ты выкарабкивался, если бы память объекта базового класса была частью памяти унаследованного? В результате с линеаризацией или без у тебя всё равно оставалась бы проблема двух экземпляров класса в вершине ромба. В C++ она худо-бедно решается виртуальным наследованием, в питоне всё наследование получается виртуальным, поэтому нет хотя бы этой части проблемы. Плюс днамическая утиная типизация, благодаря чему нет необходимости преобразовывать ссылки к ссылкам на базовый тип.
|
|
Сообщ.
#182
,
|
|
|
|
Зачем вообще привлекать терминологию c++? В Питоне нет обычного и виртуального наследования, как это понимается в c++. Проблема ромба просто устраняется за счёт линеаризации.
|
|
Сообщ.
#185
,
|
|
|
|
Цитата Shaggy @ а зачем? А как ты в типе параметра метода указываешь, что он должен удовлетворять нескольким интерфейсам? Т.е. например ![]() ![]() interface ReadWriter extends Reader, Writer {} ... public void someMethod(ReadWriter x) { ... } |
|
Сообщ.
#186
,
|
|
|
|
Я-таки нашёл свой эксперимент.
Внимание! предупреждаю: ![]() ![]() struct NullType {}; template <typename L, bool V, typename R> struct TList; template <typename T, bool V1, typename L, typename R, bool V2> struct TList<T, V1, TList<L, V2, R> > { typedef T Head; typedef TList<L, V2, R> Tail; }; template <typename T, bool V> struct TList<T, V, NullType> { typedef T Head; typedef NullType Tail; }; template <typename T, bool V1, typename L, typename R, bool V2> struct TList<TList<L, V2, R>, V1, T>; template <typename T, bool V> struct TList<NullType, V, T>; template <typename T, size_t N> struct GetType; template <typename L, bool V, typename R, size_t N> struct GetType<TList<L, V, R>, N> { typedef typename GetType<R, N-1>::result result; }; template <typename L, bool V, typename R> struct GetType<TList<L, V, R>, 0> { typedef L result; }; template <typename T, size_t I> struct Item { T node; Item(): node(T()) {} }; template <typename T, size_t N, typename Z> struct GenHierarchy; template <typename L, typename R, size_t N, typename Z> struct GenHierarchy<TList<L, false, R>, N, Z> : Item<L, N>, GenHierarchy<R, N+1, Z> { }; template <typename L, typename R, size_t N, typename Z> struct GenHierarchy<TList<L, true, R>, N, Z> : virtual Item<L, N>, GenHierarchy<R, N+1, Z> { }; template <typename L, size_t N, typename Z> struct GenHierarchy<TList<L, false, NullType>, N, Z> : Item<L, N>, virtual GenHierarchy<NullType, N+1, Z> { typedef Z result; }; template <typename L, size_t N, typename Z> struct GenHierarchy<TList<L, true, NullType>, N, Z> : virtual Item<L, N>, virtual GenHierarchy<NullType, N+1, Z> { typedef Z result; }; template <size_t N, typename Z> struct GenHierarchy<NullType, N, Z> {}; template <typename T> struct GenerateTree: GenHierarchy<T, 0, T> { template <size_t I> typename GetType<T, I>::result& field() { return static_cast<Item<typename GetType<T, I>::result, I>&>(*this).node; } }; template <size_t I, typename Gen> typename GetType<typename Gen::result, I>::result& field(Gen& gen) { return static_cast<Item<typename GetType<typename Gen::result, I>::result, I>&>(gen).node; } ![]() ![]() typedef TList<int, false, // struct { separated int 0; TList<int, true, // shared int 1; TList<float, false, // separated float 2; TList<wchar_t, false, // separated wchar_t 3; TList<int, false, // separated int 4; TList<float, true, NullType> > > > > > TypeList; // shared float 5; }; ![]() ![]() struct Right: GenerateTree<TypeList> {}; struct Left : GenerateTree<TypeList> {}; struct Tuple: Right, Left {}; Для доступа к совмещаемым полям можно использовать последнюю функцию field<N>(), указав номер поля в N и экземпляр структуры в параметре. Для совмещаемых этого достаточно, однако для отделённых следует заботиться о разрешении неоднозначности и использовать метод GenerateTree<>::field<N>() нашего экземпляра. Пример: ![]() ![]() template <typename Dst, typename Src> Dst& select(Src& src) { return static_cast<Dst&>(src); } int main() { Tuple tuple; select<Right>(tuple).field<0>() = 123; select<Right>(tuple).field<1>() = 456; select<Right>(tuple).field<2>() = 789.147f; select<Right>(tuple).field<3>() = L'q'; select<Right>(tuple).field<4>() = 258; select<Right>(tuple).field<5>() = 147.789f; select<Left >(tuple).field<0>() = 321; select<Left >(tuple).field<1>() = 654; select<Left >(tuple).field<2>() = 987.369f; select<Left >(tuple).field<3>() = L'Q'; select<Left >(tuple).field<4>() = 852; select<Left >(tuple).field<5>() = 963.987f; std::wcout<< select<Right>(tuple).field<0>() << '\t' << select<Right>(tuple).field<1>() << '\t' << select<Right>(tuple).field<2>() << '\t' << select<Right>(tuple).field<3>() << '\t' << select<Right>(tuple).field<4>() << '\t' << select<Right>(tuple).field<5>() << '\n' << select<Left >(tuple).field<0>() << '\t' << select<Left >(tuple).field<1>() << '\t' << select<Left >(tuple).field<2>() << '\t' << select<Left >(tuple).field<3>() << '\t' << select<Left >(tuple).field<4>() << '\t' << select<Left >(tuple).field<5>() << std::endl; field<1>(tuple) = 456; field<5>(tuple) = 147.789f; std::wcout<< field<1>(tuple) << '\t' << field<5>(tuple) << '\n' << sizeof tuple << std::endl; } |
|
Сообщ.
#187
,
|
|
|
|
Цитата korvin @ А как ты в типе параметра метода указываешь, что он должен удовлетворять нескольким интерфейсам? никак, нет необходимости все нужные интерфейсы запрашиваются явно |
|
Сообщ.
#188
,
|
|
|
|
D_KEY, ты же сам решил питон с C++ сравнить. Без деталей реализации сравнение бессмысленно, я и написал, что реализация наследования в питоне слишком отличается от таковой в C++. И попытка реализации в C++ чего-то подобного питоновскому обойдётся слишком дорого.
|
|
Сообщ.
#189
,
|
|
|
|
Сравнение без деталей реализации не бессмысленно, оно показывает разницу подходов и принципов, лежащих в основе языков.
|
|
Сообщ.
#190
,
|
|
|
|
Цитата Shaggy @ все нужные интерфейсы запрашиваются явно В смысле так: ![]() ![]() procedure DoSomething (x: InterfacedObject); var r: Reader; w: Writer; begin if not (x is Reader) then Exit; if not (x is Writer) then Exit; r := x as Reader; w := x as Writer; ... что ли? |
|
Сообщ.
#191
,
|
|
|
|
![]() ![]() r:=x as Reader; // или if Supports(x,Reader,r) then |
|
Сообщ.
#192
,
|
|
|
|
Ну я так и написал. А если интерфейсов будет больше? Как-то это криво и неудобно.
|
|
Сообщ.
#193
,
|
|
|
|
Цитата korvin @ Ну я так и написал нет 1. is с интерфейсами не работает 2. даже если бы работала, зачем делать две проверки вместо одной? Цитата korvin @ А если интерфейсов будет больше? Как-то это криво и неудобно это такая агитация за "god/magic method"? |
|
Сообщ.
#194
,
|
|
|
|
Цитата Shaggy @ нет 1. is с интерфейсами не работает Да не суть важно. Цитата Shaggy @ 2. даже если бы работала, зачем делать две проверки вместо одной? Т.е. при присваивании ![]() ![]() r := x as Reader; происходит проверка? А если x не реализует Reader, что произойдет? Выброс исключения? Цитата Shaggy @ это такая агитация за "god/magic method"? Нет, при чем тут это? Где тут god'овость? ![]() ![]() interface Reader { Read(...) } interface Writer { Write(...) } interface Opener { Open() : Error } interface Closer { Close() } interface OpenReadWriteCloser { Open, Reader, Writer, Closer } procedure DoSomething(x : OpenReadWriteCloser) Error { var request, response : Data if err := x.Open(); err != nil { return err } delay x.Close() x.Read(&request) ... x.Write(response) } |
|
Сообщ.
#195
,
|
|
|
|
Цитата korvin @ происходит проверка? А если x не реализует Reader, что произойдет? Выброс исключения да supports возвращает false а с помощью queryinterface можно и причину узнать используй что тебе удобнее, но не всё же сразу Цитата korvin @ Где тут god'овость? если у тебя все интерфейсы содержат по одному методу, тогда понятно такое их количество я как-то привык создавать по интерфейсу на задачу, а не на каждое действие |