Deutsch
Germany.ruФорумы → Архив Досок→ Программирование

как правильно программировать?

785  1 2 3 4 5 все
anly постоялец19.09.09 23:10
anly
NEW 19.09.09 23:10 
в ответ Chipolino 19.09.09 20:11, Последний раз изменено 19.09.09 23:18 (anly)
В ответ на:
Еще раз повторяю, ты не имеешь понятия о чем рассуждаешь.
разумеется я рассуждаю только на основе моих знаний с++. Разве в питоне виртуальность не такая как в с++? разве в питоне динамическое приведение типа не такое как dynamic_cast в с++(за исключением того что в с++ это нужно писать явно, а в питоне это делается интерпретатором неявно, за кулисами)?
Тогда объясни.
Проклят нарушающий межи ближнего своего (Втор.27:17)
#21 
anly постоялец19.09.09 23:16
anly
NEW 19.09.09 23:16 
в ответ Chipolino 19.09.09 20:11
В ответ на:
А зачем менять аргументы ? Просто перегрузи и используй свой вариант.
интересный вопрос: зачем?
Представь себе бывает нужно поменять. Поменяешь у базового класса, поменяешь у 20ти наследников, а у 21го недоглядел, не поменял. И тогда, если у базового функция не абстрактная, то 21й наследник будет использовать именно её, а не свою специфическую. Что и есть ошибка, которая может проявиться сразу, а может и через год.
Проклят нарушающий межи ближнего своего (Втор.27:17)
#22 
Murr коренной житель20.09.09 01:25
Murr
NEW 20.09.09 01:25 
в ответ anly 19.09.09 23:16
...то 21й наследник будет использовать именно её...
------
21-й наследник будет использовать ту, которая определена правилами.
В случае Плюсов, дай бог памяти, это будет последняя из определенных в предках соответсвующих факическому типу объекта.
Учи матчасть.
Что и есть ошибка, которая может проявиться
------
Она "проявляется" при тестировании. По этому вопросу, опять таки - учи матчасть.
#23 
anly постоялец20.09.09 08:46
anly
NEW 20.09.09 08:46 
в ответ Murr 20.09.09 01:25, Последний раз изменено 20.09.09 08:57 (anly)
В ответ на:
...то 21й наследник будет использовать именно её...
------
21-й наследник будет использовать ту, которая определена правилами.
В случае Плюсов, дай бог памяти, это будет последняя из определенных в предках соответсвующих факическому типу объекта.
Учи матчасть.
Что и есть ошибка, которая может проявиться
------
Она "проявляется" при тестировании. По этому вопросу, опять таки - учи матчасть.
да вот мат часть кажись я получше знаю. Так и быть объясню вам, далеко от плюсов отошедших.
Во-первых, везёт вам что занимаетесь такими программами, что есть возможность всё протестировать. Во вторых, даже тест не гарантирует отсутствие ошибок. Особенно, если тестирует не девелопер, а тестировщик, который исходники не видит, да и частенько языка не понимает. Но даже если девелопер тестирует, тоже гарантии нет. Ошибка может проявиться только после изменений, косвенно влияющих на данный код или зависящих от данного кода.
Во вторых пример.(только по существу вопроса, т.е. виртуальности. не обращайте внимание например на утечки памяти, не хочу отвлекать от сути).
У базового класса есть виртуальная функция, которая не пустая, а что-то делает. И некоторые наследники не переопределяют её. А некоторые наследники переопределяют.
class A
{
virtual void myfun(int n);
}
class B : A
{
}
class C : A
{
virtual void myfun(int n);
}
// ..... и еще 25 наследников ...
main()
{
A* p = new B;
p->myfun(76); // вызов A::myfun()
p = new C;
p->myfun(33); // вызов С::myfun()
}
Прошло сто лет и надо добавить параметр в функцию. Этот параметр обрабатывается только в функции одного из наследников (которого я здесь даже не показал), функция базового класса(А) новый параметр просто игнорирует, класса С - тоже.
class A
{
virtual void myfun(int n, bool b);
}
в A добавил, и во всех других наследниках, которые переопределяют эту функцию, кроме С. в C не добавил, не доглядел.
В main подправим, это даже компилятор потребует.
main()
{
A* p = new B;
p->myfun(76, false); // вызов A::myfun()
p = new C;
p->myfun(33, false); // вызов A::myfun() !!!!!!!!!!!!!!!!!!! ошибка !!!!!
}
Проклят нарушающий межи ближнего своего (Втор.27:17)
#24 
  Chipolino старожил20.09.09 10:31
20.09.09 10:31 
в ответ anly 19.09.09 23:10
В ответ на:
разумеется я рассуждаю только на основе моих знаний с++. Разве в питоне виртуальность не такая как в с++? разве в питоне динамическое приведение типа не такое как dynamic_cast в с++(за исключением того что в с++ это нужно писать явно, а в питоне это делается интерпретатором неявно, за кулисами)?
Тогда объясни.

dynamic_cast работает только с полиморфными типами и связь с питоном вообще отсутствует.
Ознакомься с темой, почитай о языках с динамической типизацией.
#25 
  Chipolino старожил20.09.09 10:37
NEW 20.09.09 10:37 
в ответ anly 19.09.09 23:16
В ответ на:
Представь себе бывает нужно поменять. Поменяешь у базового класса, поменяешь у 20ти наследников, а у 21го недоглядел, не поменял. И тогда, если у базового функция не абстрактная, то 21й наследник будет использовать именно её, а не свою специфическую. Что и есть ошибка, которая может проявиться сразу, а может и через год.

Это говорит о хреновом проектировании.
Потом ты звонишь всем клиентам и просишь поменять сигнатуры функций в клиентском коде ? :-)
#26 
  Chipolino старожил20.09.09 10:49
NEW 20.09.09 10:49 
в ответ anly 20.09.09 08:46
В ответ на:
Так и быть объясню вам, далеко от плюсов отошедших.

Спасибо, о Гуру ! :-)
В ответ на:
Прошло сто лет и надо добавить параметр в функцию. Этот параметр обрабатывается только в функции одного из наследников (которого я здесь даже не показал), функция базового класса(А) новый параметр просто игнорирует, класса С - тоже.

Хоть вся твоя проблема кажется надуманной, но можно сделать вот так.
class superclass{
virtual void myfun(int n, bool b)=0;
};
class A:superclass{};
С помощью компилятора найдешь все классы.
#27 
Murr коренной житель20.09.09 12:55
Murr
20.09.09 12:55 
в ответ anly 20.09.09 08:46
везёт вам
------
Не нам везет - куЁм свое везение сами. Частенько это стоит большего количества
работы...
может проявиться только после изменений
-----
А после изменений тестировать не надо?
ошибка !!!!!
-----
Это не ошибка - это именно то, что ты написал.
И с подобными описками тоже можно бороться. Например, можно, изначально,
еще в правилах кодинга, задать требование об отсутствии использования встроенных
типов в качестве параметров и тогда это выглядит так:
class MyFuncParam { ... }
class A
{
virtual void myfun(MyFuncParam& n);
}
...etc...

тут любые изменения не затрагивают базовый код, независимо от изменений содержимого
MyFuncParam.
#28 
Murr коренной житель20.09.09 13:05
Murr
NEW 20.09.09 13:05 
в ответ Chipolino 20.09.09 10:49
С помощью компилятора найдешь все классы.
-----
Что-то меня сомнения берут. Бо, чистую виртуальную функцию обязан определять _хотя бы один_ из потомков. Как только один определит - ситуация становится эквивалентной первичной - может быть опущена в потомках.
#29 
voxel3d коренной житель20.09.09 13:22
voxel3d
NEW 20.09.09 13:22 
в ответ anly 19.09.09 23:16, Последний раз изменено 20.09.09 13:27 (voxel3d)
В ответ на:
Представь себе бывает нужно поменять. Поменяешь у базового класса, поменяешь у 20ти наследников, а у 21го недоглядел, не поменял. И тогда, если у базового функция не абстрактная, то 21й наследник будет использовать именно её, а не свою специфическую. Что и есть ошибка, которая может проявиться сразу, а может и через год.

В отличии от C++ питон выкинет исключение, а не дёрнет подходящий метод из цепочки наследования сверху. Которой и не будет вовсе. Просто, надо писать на питоне, а не на C++ с синтаксисом питона.
Наследование применяется в двух случаях - для создания функциональности в предке, чтобы не дублировать её в потомке и для реализации полиморфизма: имея ссылку или указатель на базовый класс, вызывать методы определённые в потомке. Для первой цели в питоне применяют наследование, для второй - нет.
Полиморфизм реализуют так:
class Оne:
"One"
def write(self):
print "one"
class Тwo:
"Two"
def write(self):
print "two"
def writer(dest):
dest.write(" variable ")
print "start"
obj = Оne()
writer(obj)
obj = Тwo()
writer(obj)

Классы One и Two никак не обязаны быть связаными между собой, единственное, что требуется, наличие метода write(). Если мы меняем сигнатуру где-то в одном месте, а в другом забываем это сделать:

class Оne:
"One"
def write(self, var):
print "one " + var

то вызов:

def writer(dest):
dest.write(" variable ")
obj = Тwo()
writer(obj)

сгенерирует исключение:

Traceback (most recent call last):
File "test.py", line 21, in <module>
writer(obj)
File "test.py", line 12, in writer
dest.write(" variable ")
TypeError: write() takes exactly 1 argument (2 given)


Dropbox - средство синхронизации и бэкапа файлов.
#30 
AlexOtt знакомое лицо20.09.09 13:27
AlexOtt
NEW 20.09.09 13:27 
в ответ anly 17.09.09 22:44
писать надо короткоги ясно - не должно быть ситуаций, когда один класс делает работу всего приложения через стотыщь мильонов функций-членов, или одна функция на 10 тыс строк выполняет всю работу определенной подсистемы. Тут важно грамотное проектирование, и желательно сразу с поддержкой unit-тестов...
Очень хорошой в смысле писания "правильного" кода является книжка Code Complete - там много полезных советов на такие темы.
унаследованный код тоже можно рефакторить, избавляться от дублирования кода, разбивать длиные функции на меньшие, например, центральная функция является точкой входа, и определяет логику вычислений, но из нее зовуться только другие функции, которые и выполняют всю работу.
#31 
  Chipolino старожил20.09.09 14:24
20.09.09 14:24 
в ответ Murr 20.09.09 13:05
В ответ на:
Что-то меня сомнения берут. Бо, чистую виртуальную функцию обязан определять _хотя бы один_ из потомков. Как только один определит - ситуация становится эквивалентной первичной - может быть опущена в потомках.

Если в потомке, определена, то в потомках потомка конечно не надо.
Но в его примере все наследуют от одного 'A'.
#32 
anly постоялец20.09.09 14:41
anly
NEW 20.09.09 14:41 
в ответ Chipolino 20.09.09 10:37, Последний раз изменено 20.09.09 14:55 (anly)
В ответ на:
Это говорит о хреновом проектировании.
дык, а я о чем говорю! Но выбирать уже не приходится. Ты пришел на работу и у тебя есть хреново спроектированная программа. Те люди которые её писали уже здесь не работают. И твоя задача перепроектировать её получше. Эту задачу вообщето тебе начальство не ставит, начальству надо чтоб притензий от заказчиков не было и не более. Но тебе в этом дерьме ковыряться и поэтому ты сам хочешь навести там порядок, на свой страх и риск. Так вот каждая виртуальная функция усложняет эту задачу. Т.к. ошибку, которую я привёл в примере, можно обнаружить только в результате тестирования. А протестировать огромную программу не всегда возможно. Просто хотя бы из за отсутствия времени. Там где нет виртуальности - проще, т.к. об ошибке сообщит компилятор, и ты никуда не денешся - подправиш.
Виртуальность хорошая вещь, но использовать её нужно только там где без нее не обойтись. И в шею гнать надо программистов которые 'на всякий случай' делают каждую функцию виртуальной. А питон сразу делает это, даже тебя не спросит...
В ответ на:
Потом ты звонишь всем клиентам и просишь поменять сигнатуры функций в клиентском коде ? :-)
не понял. клиенты - простые пользователи и ни о чём вышеописанном не подозревают.
Проклят нарушающий межи ближнего своего (Втор.27:17)
#33 
anly постоялец20.09.09 14:49
anly
NEW 20.09.09 14:49 
в ответ voxel3d 20.09.09 13:22
В ответ на:
В отличии от C++ питон выкинет исключение, а не дёрнет подходящий метод из цепочки наследования сверху
это тоже ошибка выполнения, которая обнаруживается только тестированием.
Проклят нарушающий межи ближнего своего (Втор.27:17)
#34 
voxel3d коренной житель20.09.09 15:01
voxel3d
NEW 20.09.09 15:01 
в ответ anly 20.09.09 14:49
В ответ на:
это тоже ошибка выполнения, которая обнаруживается только тестированием.

Unittest входит в базовую библиотеку питона, юнит-тестирование выявляет эту ошибку (в С++, кстати, нет). Проверка же типов / сигнатур в рантайме - особенность динамических языков.
Dropbox - средство синхронизации и бэкапа файлов.
#35 
anly постоялец20.09.09 15:13
anly
NEW 20.09.09 15:13 
в ответ voxel3d 20.09.09 15:01
В ответ на:
Unittest входит в базовую библиотеку питона, юнит-тестирование выявляет эту ошибку (в С++, кстати, нет).
для меня, как незнатока питона, это звучит несколько "волшебно". Т.е. юниттест "чудестным" образом обнаружит ошибку.
Разве этот тест не сам программист должен написать? Разве всегда возможно написать тест который обнаружит любые ошибки? А тест для теста тоже надо писать? ведь и в тесте может ошибка оказаться. Я не против юниттестов, наверняка очень хорошая практика, но не панацея, 100процентной гарантии нет.
Проклят нарушающий межи ближнего своего (Втор.27:17)
#36 
voxel3d коренной житель20.09.09 15:24
voxel3d
NEW 20.09.09 15:24 
в ответ anly 20.09.09 15:13, Последний раз изменено 20.09.09 15:27 (voxel3d)
Это не "любая ошибка". Программа 100% валится на попытке вызова метода - соответственно, независимо от того, что именно будет проверять юнит-тест, ошибка будет выявлена.
Тесты, да, пишет сам программист.
В ответ на:
Я не против юниттестов, наверняка очень хорошая практика, но не панацея, 100процентной гарантии нет.

Это у тебя с твоим вариантом полиморфизма нет, а в тут есть.
Dropbox - средство синхронизации и бэкапа файлов.
#37 
anly постоялец20.09.09 15:34
anly
NEW 20.09.09 15:34 
в ответ voxel3d 20.09.09 15:24
В ответ на:
Это у тебя с твоим вариантом полиморфизма нет, а в питоне есть.
чтобы тест выявил ошибку нужно в тесте вызвать эту функцию. а ежели не вызвал? т.е. не написал именно этого теста. что тогда? (может не ты, а тот кто писал этот тест много лет назад)
Я это говорю только чтобы подчеркнуть что ошибки компиляции гораздо безопаснее ошибок выполнения.
Проклят нарушающий межи ближнего своего (Втор.27:17)
#38 
Simple Nothing is f*cked20.09.09 16:01
Simple
NEW 20.09.09 16:01 
в ответ anly 20.09.09 14:41, Последний раз изменено 20.09.09 16:04 (Simple)
http://www.amazon.de/Working-Effectively-Legacy-Robert-Martin/dp/0131177052
ps
В ответ на:
Но тебе в этом дерьме ковыряться и поэтому ты сам хочешь навести там порядок, на свой страх и риск.

Эта цель должна быть поставлена сверху, иначе можно сразу забить. У меня та же проблема, и время на наведение порядка уже выделено. Надо грамотно работать с начальством ;)
#39 
voxel3d коренной житель20.09.09 16:29
voxel3d
NEW 20.09.09 16:29 
в ответ anly 20.09.09 15:34
Ошибки выявляемые на этапе компиляции безопаснее, только все разговоры об этом в сообществе С++ сильно преувеличивают значимость статической типизации.
Dropbox - средство синхронизации и бэкапа файлов.
#40 
1 2 3 4 5 все