Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.145.107.181] |
|
Страницы: (16) « Первая ... 10 11 [12] 13 14 ... Последняя » все ( Перейти к последнему сообщению ) |
Сообщ.
#166
,
|
|
|
Цитата Qraizer @ Более-менее придумали. Сиречь придумали универсальный протокол, придерживаться которого должны обе стороны.Ага? |
Сообщ.
#167
,
|
|
|
Цитата korvin @ Давай пример кодом: как было до рефакторинга, как стало и что не так, а то я что-то не могу понять, на что ты жалуешься. Ну вот был такой класс: class A { public: virtual ~A() = default; virtual std::string foo() const { return "A"; } }; И тест void testA() { A a; assert(a.foo() == "A"); } И вот какой-то из наследников: class B: public A { public: virtual std::string foo() const { return "B"; } }; И его тест void testB() { B b; assert(b.foo() == "B"); } В реальном коде используем как-то так: auto ptr= factory->make_instance(...); ... std::cout << ptr->foo() << std::endl; Все ок, если создадим экземпляр B, то будет выведено "B". Теперь рефакторили и заменили сигнатуру: class A { public: virtual ~A() = default; virtual std::string foo(int x) const { return "A"; } }; Подправили тесты: void testA() { A a; assert(a.foo(10) == "A"); } Подправили использование: auto ptr= factory->make_instance(...); ... std::cout << ptr->foo(10) << std::endl; Подправили тех наследников, о которых помнили. А вот про B забыли. В результате, теперь в случае экземпляра B, выводиться будет A. И, внезапно, если бы там был override, то компилятор бы ругался и никакой проблемы бы не возникло. Добавлено Цитата korvin @ Зачем это всё? Чтобы лучше всё структурировать вместо каши из override и non-override методов, чтобы IDE лучше понимала семантику кода, в частности выполняла семантически более точный рефакторинг при изменении сигнатуры методов «родителей», который мы тут обсуждали. + один набор юнит-тестов на разные реализации. И при этом добавить некоторую гибкость в виде протоколов. Я правильно понимаю, что это все потребует нового языка? Цитата Хз как там в ваших D/Rust/C#, но без аналога Go'шных интерфейсов или OCaml'овских object type'ов в Java грустновато. Вот тут не понял. Зачем тебе goшные интерфейсый в java? Цитата Но это только интерфейсы, осталось разобрать наследование реализаций (классов)… Это будет ближе к практике? Добавлено Цитата D_KEY @ И, внезапно, если бы там был override, то компилятор бы ругался и никакой проблемы бы не возникло. Изначальный пример http://ideone.com/cac3Ss После рефакторинга http://ideone.com/kuCrur Если бы был override http://ideone.com/SieIBM Цитата error: ‘std::__cxx11::string B::foo() const’ marked ‘override’, but does not override std::string foo() const override |
Сообщ.
#168
,
|
|
|
Цитата D_KEY @ И тест Цитата D_KEY @ И его тест Цитата D_KEY @ Все ок, если создадим экземпляр B, то будет выведено "B". В твоем примере слово virtual абсолютно бессмысленно. Создай подобие интерфейса и перепиши свой код вот так: struct Base { virtual string foo() const = 0; virtual ~Base() = 0; }; class A : public Base { public: virtual ~A() = default; virtual std::string foo() const { return "A"; } }; Потом перепиши тесты: void testA() { std::uniqe_ptr<Base> pA = std::make_uniqe<A>(); assert(pA->foo(10) == "A"); } А вот после этого меняй сигнатуру. Тогда будет правильно. Добавлено Ну или хотя бы в тесте testB сделай динамическое создание класса B, присвоей его переменной базового класса А. У тебя ведь А базовый, присутствуют виртуальные функции. Соответственно ты будешь работать с базовым классом, а не напрямую с B/A. |
Сообщ.
#169
,
|
|
|
Цитата Wound @ В твоем примере слово virtual абсолютно бессмысленно. Ты о чем-то своем. Мы обсуждаем пользу override при рефакторинге. При чем тут интерфейсы? Добавлено Цитата Wound @ присвоей его переменной базового класса А. И часто ты в тестах такой каст делаешь? |
Сообщ.
#170
,
|
|
|
Цитата D_KEY @ Ты о чем-то своем. Мы обсуждаем пользу override при рефакторинге. При чем тут интерфейсы? Ну речь то зашла изначально про интефрейсы. Цитата D_KEY @ И часто ты в тестах такой каст делаешь? Какой такой каст делаю? Это обычный дин. полиморфизм называется. У тебя в твоем примере тесты отличаются от реальной работы классов. Т.е. тесты живут своей жизнью, программа живет своей жизнью. Не совсем понятно что ты тестишь. Посмотри на свои функции тестирования, и посмотри на использование: Цитата D_KEY @ auto ptr= factory->make_instance(...); ... std::cout << ptr->foo(10) << std::endl; Я не вижу использования классов A/B, зато я вижу нечто базовое, через которое может вызваться в зависимости от типа тот или другой метод. Раз ты у себя в коде пишешь: auto ptr= factory->make_instance(...); Значит это же у тебя должно быть и в тестах. Либо на крайняк, если ты не хочешь тестировать фабрику, должно быть так, как я написал выше, а именно работа через базовый класс. |
Сообщ.
#171
,
|
|
|
Цитата Wound @ Ну речь то зашла изначально про интефрейсы. Это обсуждение уже давно откололось от того Цитата У тебя в твоем примере тесты отличаются от реальной работы классов. Т.е. тесты живут своей жизнью, программа живет своей жизнью. Не совсем понятно что ты тестишь. Работу класса я тестирую. Цитата Раз ты у себя в коде пишешь: auto ptr= factory->make_instance(...); Значит это же у тебя должно быть и в тестах Это уже будет не юнит-тестирование. |
Сообщ.
#172
,
|
|
|
Цитата D_KEY @ Это уже будет не юнит-тестирование. А что это будет? Цитата D_KEY @ Работу класса я тестирую. В таком случае у тебя нет ошибки. И поведение абсолютно предсказуемое. К чему претензия? Добавлено D_KEY, вот представь я пишу все тоже самое, но у меня B не наследуется от А, ну просто два разных класса, с одинаковым методом. А потом вдруг кто то подумает и решит короче, B унаследовать от А, и заодно изменит вот как ты сигнатуру у А. Ну и все далее как у тебя. Что в этом случае не так? Тесты плохие? Или что? |
Сообщ.
#173
,
|
|
|
Цитата Wound @ D_KEY, вот представь я пишу все тоже самое, но у меня B не наследуется от А, ну просто два разных класса, с одинаковым методом. А потом вдруг кто то подумает и решит короче, B унаследовать от А, и заодно изменит вот как ты сигнатуру у А. Ну и все далее как у тебя. Что в этом случае не так? Тесты плохие? Или что? Просто странный код будет Я не понимаю, о чем ты сейчас. Мы говорим о пользе override. Я просто привел пример, когда он поможет. И все. |
Сообщ.
#174
,
|
|
|
Цитата D_KEY @ Просто странный код будет Я не понимаю, о чем ты сейчас. Мы говорим о пользе override. Я просто привел пример, когда он поможет. И все. Так ты прочитай что тебе написали в этом посте: Rust vs C++ (сообщение #3808312) И потом посмотри что ты ответил. Тебе говорят, что override нафиг не нужен, например в той же Java, потому что надо писать вот так то и так то, вот об этом написано: Цитата korvin @ Зачем это всё? Чтобы лучше всё структурировать вместо каши из override и non-override методов, чтобы IDE лучше понимала семантику кода, в частности выполняла семантически более точный рефакторинг при изменении сигнатуры методов «родителей», который мы тут обсуждали. + один набор юнит-тестов на разные реализации. И при этом добавить некоторую гибкость в виде протоколов. Хз как там в ваших D/Rust/C#, но без аналога Go'шных интерфейсов или OCaml'овских object type'ов в Java грустновато. А ты в ответ пишешь, что он будет делать, если забудет гдето там написать override. override - синтаксический сахар по сути, который просто лишний раз может тебе сказать что у тебя не совпадают сигнатуры базового и производного методов. Но использование его, еще не означает что ты проектируешь систему правильно. И раз у тебя возникают такие ошибки, и тебе помог override, значит скорее всего будут и другие ошибки, на которые синтаксического сахара не найдется. Ну это как скажем assert что ли. То что он есть, еще не спасает тебя от ошибок. |
Сообщ.
#175
,
|
|
|
Цитата Wound @ может тебе сказать что у тебя не совпадают сигнатуры базового и производного методов. Так и я про то. Цитата Но использование его, еще не означает что ты проектируешь систему правильно. А кто говорит о проектировании систем? Цитата И раз у тебя возникают такие ошибки, и тебе помог override, значит скорее всего будут и другие ошибки, на которые синтаксического сахара не найдется. Например? Добавлено Цитата Wound @ потому что надо писать вот так то и так то Это уже совсем из другой области вопрос. |
Сообщ.
#176
,
|
|
|
Цитата D_KEY @ Например? Например что у тебя factory->make_instance(...); будет работать не так, как ты ожидаешь. Добавлено Цитата D_KEY @ Это уже совсем из другой области вопрос. Ну не знаю, просто у вас тогда странный разговор получается. Тебе объясняют почему в принципе не нужен override, а ты объясняешь от чего он спасает. Так если не писать так, как ты показал - то нафиг этот override нужен то? |
Сообщ.
#177
,
|
|
|
А причём тут вообще проектирование? override ему ортогонален совершенно.
|
Сообщ.
#178
,
|
|
|
Между прочим в С++ override появился сравнительно недавно. И до него как то не особо припомню вот таких вот проблем. Обычно все разруливалось ЮТ.
Добавлено Цитата OpenGL @ А причём тут вообще проектирование? override ему ортогонален совершенно. Ну как выяснилось у некоторых не ортогонален. |
Сообщ.
#179
,
|
|
|
Цитата Wound @ Цитата D_KEY @ Например? Например что у тебя factory->make_instance(...); будет работать не так, как ты ожидаешь. С чего вдруг? Цитата Тебе объясняют почему в принципе не нужен override, а ты объясняешь от чего он спасает. Так если не писать так, как ты показал - то нафиг этот override нужен то? Потому что это всего-лишь пример. Иллюстрация. Ты не всегда сможешь отследить изменение сигнатуры в реальном проекте. Добавлено Цитата Wound @ Между прочим в С++ override появился сравнительно недавно. И до него как то не особо припомню вот таких вот проблем. А для чего добавили, на твой взгляд? Цитата Обычно все разруливалось ЮТ. Во-первых, ЮТ не являются частью языка. Во-вторых, я мало видел тестов, где бы кастили к базовому классу. Возможно, все кастят, а мне попадалось говно. Но это ничего на самом деле не меняет. |
Сообщ.
#180
,
|
|
|
Цитата D_KEY @ С чего вдруг? Да просто так, оно ж у тебя в тестах не тестируется. Мало ли там что пойдет не так, вместо класса A, создастся класс B например или наоборот. Цитата D_KEY @ Потому что это всего-лишь пример. Иллюстрация. Ты не всегда сможешь отследить изменение сигнатуры в реальном проекте. А раньше как отслеживал? Цитата D_KEY @ А для чего добавили, на твой взгляд? А они как бы все в язык несут, все новомодности модные собирают со всех языков и несут в язык. Чтоб было. Ну как синтаксический сахар конечно пойдет. Я ж не против override'ов. Цитата D_KEY @ Во-первых, ЮТ не являются частью языка. Во-вторых, я мало видел тестов, где бы кастили к базовому классу. Возможно, все кастят, а мне попадалось говно. Но это ничего на самом деле не меняет. Незнаю, мне напротив попадалось другое. Пишешь ЮТ - которые эмулируют работу, с помощью тех же mock объектов. Как правило помимо самих функций - тестируется еще и функционал который они делают. Потому как в 99% случаев, бывает такое, что для того, что бы юзнуть функцию в ЮТ, для нее нужно настроить окружение. А это подразумевает имитирование работы части функционала. Например там функция ждет от тебя какой нибудь коннектор, провайдер, поток с данными и т.д. чтоб дальше с ним работать, или например еще что то, и а те в свою очередь, для того чтоб вернули ожидаемые значения могут еще что то принимать, что в свою очередь может принимать еще другое. И в итоге ты начинаешь делать mock объекты и эмулировать работу программы в ЮТ. Где практически все косяки, в том числе и те, которые ты написал зачастую всплывают. |