Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.143.244.83] |
|
Страницы: (16) 1 [2] 3 4 ... 15 16 все ( Перейти к последнему сообщению ) |
Сообщ.
#16
,
|
|
|
Мне кажется - это не недостаток, а фишка! Наследования, как я понял, совсем нет. Ни данных, ни реализации. И это упрощает в некотором смысле архитектуру. Не нужно заботиться, что, где, кого перекрывает, какие классы (при множественном наследовании) могут нечаянно включиться N или даже M! раз ... Вместо наследования - применяем агрегацию! См. сравнимый по функционалу код: C++: #include <iostream> using namespace std; struct A { int a; A(int x); virtual void print(); }; struct B : A { int b; B(int x, int y); void print() override; }; struct C : B { int c; C(int x, int y, int z); void print() override; }; A::A(int x):a(x) { } void A::print() { cout << a << endl; } B::B(int x, int y):A(x),b(y) { } void B::print() { A::print(); cout << b << endl; } C::C(int x, int y, int z):B(x,y),c(z) { } void C::print() { B::print(); cout << c << endl; } int main() { C c = {1,2,3}; c.print(); return 0; } Rust: use std::io::stdin; struct A { a: u32 } struct B { a: A, b: u32 } struct C { b: B, c: u32 } trait Print { fn print(&self); } impl Print for A { fn print(&self) { println!("{}",self.a) } } impl Print for B { fn print(&self) { self.a.print(); println!("{}",self.b) } } impl Print for C { fn print(&self) { self.b.print(); println!("{}",self.c) } } fn main() { let C = C{b:B{a:A{a:1},b:2},c:3}; C.print(); } Если говорить про вкусовщину - меня код Раст радует больше! |
Сообщ.
#17
,
|
|
|
А что тебе мешало в C++ написать примерно так же?
#include <iostream> using namespace std; struct Print { virtual void print() = 0; }; struct A : Print { int a; A(int x); void print() override; }; struct B : Print { A a; int b; B(int x, int y); void print() override; }; struct C : Print { B b; int c; C(int x, int y, int z); void print() override; }; A::A(int x):a(x) { } void A::print() { cout << a << endl; } B::B(int x, int y):a(x),b(y) { } void B::print() { a.print(); cout << b << endl; } C::C(int x, int y, int z):b(x,y),c(z) { } void C::print() { b.print(); cout << c << endl; } int main() { C c = {1,2,3}; c.print(); return 0; } Добавлено Цитата JoeUser @ И это упрощает в некотором смысле архитектуру. Не нужно заботиться, что, где, кого перекрывает, какие классы (при множественном наследовании) могут нечаянно включиться N или даже M! раз ... В C++ ты можешь организовать свою архитектуру так же. А вот в Rust выбора нет |
Сообщ.
#18
,
|
|
|
Цитата D_KEY @ А что тебе мешало в C++ написать примерно так же? Не мешало. Наоборот - я хотел от наследования С++ перейти к агрегации на Расте, без потери функционала. Цитата D_KEY @ В C++ ты можешь организовать свою архитектуру так же. А вот в Rust выбора нет Вот тут давай уточнять! Правильнее бы было сказать, имхо, так: "В C++ ты можешь организовать свою C++ - шную архитектуру так же. А вот в Rust выбора нет". Добавлено D_KEY, и да ... твой код не эквивалентен "растовскому"! Я сперва тоже приплел виртуальные функции, потом подумал, что на 3 структурах можно и без них. |
Сообщ.
#19
,
|
|
|
Цитата JoeUser @ D_KEY, и да ... твой код не эквивалентен "растовскому"! Я сперва тоже приплел виртуальные функции, потом подумал, что на 3 структурах можно и без них. Разница только в том, что в Rust отвязаны структуры и impl. Ты про это? |
Сообщ.
#20
,
|
|
|
Цитата D_KEY @ Нет. Наличие виртуальных Функций - это уже наличие VMT. А это не по фэн-шую Ты про это? |
Сообщ.
#21
,
|
|
|
Цитата JoeUser @ Цитата D_KEY @ Нет. Наличие виртуальных Функций - это уже наличие VMT. А это не по фэн-шую Ты про это? Ты думаешь, что Impl'ы как-то иначе устроены? |
Сообщ.
#22
,
|
|
|
Сообщ.
#23
,
|
|
|
Цитата JoeUser @ Так оттуда же(про динамическую диспетчерезацию): Цитата However, this comes at the cost of requiring slower virtual function calls, and effectively inhibiting any chance of inlining and related optimisations from occurring. Добавлено А в Representation заглядывал? Добавлено Цитата The methods of the trait can be called on a trait object via a special record of function pointers traditionally called a 'vtable' (created and managed by the compiler). |
Сообщ.
#24
,
|
|
|
D_KEY, э не ... так не пойдет! Давай пруф из доков, где говорится, что любая реализация "методов" посредством блока impl породжает одиночную дичпетчеризацию (через VMT). Иначе я моя твоя не понимать. И это ... учитывай, что книгу по Расту я прочел только один раз, в меру своей внимательности! Считай - махровый нубас!
|
Сообщ.
#25
,
|
|
|
JoeUser, смотри в раздел Representation по твоей ссылке. Там даже та же терминология используется(vtable).
|
Сообщ.
#26
,
|
|
|
Цитата D_KEY @ про динамическую диспетчерезацию Погоди ... так это вырвано из контекста??? А при статической (как у меня в примере)? Там тоже Раст будет VMT (ну или что-то подобное) городить??? Я в это не поверю! Добавлено Цитата D_KEY @ ам даже та же терминология используется(vtable). Ну да - для динамической диспетчеризации! Но откуда такое обобщение: Цитата D_KEY @ Ты думаешь, что Impl'ы как-то иначе устроены? ??? Читается как "всегда" |
Сообщ.
#27
,
|
|
|
В примере JoeUser-а же компилятору точный тип известен, так что никакого виртуального вызова быть не должно. Хотя изначально разговор был про наличие VMT - возможно, компилятор эту таблицу всё же генерирует
|
Сообщ.
#28
,
|
|
|
Цитата OpenGL @ возможно, компилятор эту таблицу всё же генерирует Покажите, что это всегда "да" - и я забуду про Раст Скрытый текст По поводу терминологии. Я применил термин "агрегация" как альтернатива наследованию. Покак еще не осознал глубину всех глубин. Возможно был не прав. Есть еще альтернативный вариант - "композиция". Терки об этом тут. Будем еще почитать! |
Сообщ.
#29
,
|
|
|
Для приведенного плюсового кода компилятор вполне может так же сгенерировать код без обращения к vtable. Это же вопрос оптимизации.
В C++ для статической диспетчерезации вообще будет достаточно обычных перегруженных функций в данном примере В более сложных случаях - шаблоны. Добавлено Но вообще подход Rust здравый. Я помню еще давно в дельфийских холиварах как-то поднимал вопрос о том, зачем, по большому счету разделять понятия статических "концептов" и динамических "интерфейсов". |
Сообщ.
#30
,
|
|
|
Цитата JoeUser @ Покажите, что это всегда "да" - и я забуду про Раст А почему не должен создавать? Если ты создал трейт, который является trait object-ом, то по-моему вполне естественно ожидать, что ты будешь использовать его именно в таком контексте. Если это не так (что, кстати, в расте не редкость), то в общем-то только и остаётся, что надеяться на оптимизатор, который сообразит, что виртуальные вызовы ты не используешь. |