Вход на сайт
как правильно программировать?
NEW 19.09.09 23:10
Тогда объясни.
В ответ на:
Еще раз повторяю, ты не имеешь понятия о чем рассуждаешь.
разумеется я рассуждаю только на основе моих знаний с++. Разве в питоне виртуальность не такая как в с++? разве в питоне динамическое приведение типа не такое как dynamic_cast в с++(за исключением того что в с++ это нужно писать явно, а в питоне это делается интерпретатором неявно, за кулисами)?Еще раз повторяю, ты не имеешь понятия о чем рассуждаешь.
Тогда объясни.
Проклят нарушающий межи ближнего своего (Втор.27:17)
NEW 19.09.09 23:16 
Представь себе бывает нужно поменять. Поменяешь у базового класса, поменяешь у 20ти наследников, а у 21го недоглядел, не поменял. И тогда, если у базового функция не абстрактная, то 21й наследник будет использовать именно её, а не свою специфическую. Что и есть ошибка, которая может проявиться сразу, а может и через год.
в ответ Chipolino 19.09.09 20:11
В ответ на:
А зачем менять аргументы ? Просто перегрузи и используй свой вариант.
интересный вопрос: зачем? А зачем менять аргументы ? Просто перегрузи и используй свой вариант.

Представь себе бывает нужно поменять. Поменяешь у базового класса, поменяешь у 20ти наследников, а у 21го недоглядел, не поменял. И тогда, если у базового функция не абстрактная, то 21й наследник будет использовать именно её, а не свою специфическую. Что и есть ошибка, которая может проявиться сразу, а может и через год.
Проклят нарушающий межи ближнего своего (Втор.27:17)
NEW 20.09.09 01:25
в ответ anly 19.09.09 23:16
...то 21й наследник будет использовать именно её...
------
21-й наследник будет использовать ту, которая определена правилами.
В случае Плюсов, дай бог памяти, это будет последняя из определенных в предках соответсвующих факическому типу объекта.
Учи матчасть.
Что и есть ошибка, которая может проявиться
------
Она "проявляется" при тестировании. По этому вопросу, опять таки - учи матчасть.
------
21-й наследник будет использовать ту, которая определена правилами.
В случае Плюсов, дай бог памяти, это будет последняя из определенных в предках соответсвующих факическому типу объекта.
Учи матчасть.
Что и есть ошибка, которая может проявиться
------
Она "проявляется" при тестировании. По этому вопросу, опять таки - учи матчасть.
NEW 20.09.09 08:46
Так и быть объясню вам, далеко от плюсов отошедших.
Во-первых, везёт вам что занимаетесь такими программами, что есть возможность всё протестировать. Во вторых, даже тест не гарантирует отсутствие ошибок. Особенно, если тестирует не девелопер, а тестировщик, который исходники не видит, да и частенько языка не понимает. Но даже если девелопер тестирует, тоже гарантии нет. Ошибка может проявиться только после изменений, косвенно влияющих на данный код или зависящих от данного кода.
Во вторых пример.(только по существу вопроса, т.е. виртуальности. не обращайте внимание например на утечки памяти, не хочу отвлекать от сути).
У базового класса есть виртуальная функция, которая не пустая, а что-то делает. И некоторые наследники не переопределяют её. А некоторые наследники переопределяют.
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() !!!!!!!!!!!!!!!!!!! ошибка !!!!!
}
В ответ на:
...то 21й наследник будет использовать именно её...
------
21-й наследник будет использовать ту, которая определена правилами.
В случае Плюсов, дай бог памяти, это будет последняя из определенных в предках соответсвующих факическому типу объекта.
Учи матчасть.
Что и есть ошибка, которая может проявиться
------
Она "проявляется" при тестировании. По этому вопросу, опять таки - учи матчасть.
да вот мат часть кажись я получше знаю. ...то 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)
NEW 20.09.09 10:31
dynamic_cast работает только с полиморфными типами и связь с питоном вообще отсутствует.
Ознакомься с темой, почитай о языках с динамической типизацией.
в ответ anly 19.09.09 23:10
В ответ на:
разумеется я рассуждаю только на основе моих знаний с++. Разве в питоне виртуальность не такая как в с++? разве в питоне динамическое приведение типа не такое как dynamic_cast в с++(за исключением того что в с++ это нужно писать явно, а в питоне это делается интерпретатором неявно, за кулисами)?
Тогда объясни.
разумеется я рассуждаю только на основе моих знаний с++. Разве в питоне виртуальность не такая как в с++? разве в питоне динамическое приведение типа не такое как dynamic_cast в с++(за исключением того что в с++ это нужно писать явно, а в питоне это делается интерпретатором неявно, за кулисами)?
Тогда объясни.
dynamic_cast работает только с полиморфными типами и связь с питоном вообще отсутствует.
Ознакомься с темой, почитай о языках с динамической типизацией.
20.09.09 10:37
Это говорит о хреновом проектировании.
Потом ты звонишь всем клиентам и просишь поменять сигнатуры функций в клиентском коде ? :-)
в ответ anly 19.09.09 23:16
В ответ на:
Представь себе бывает нужно поменять. Поменяешь у базового класса, поменяешь у 20ти наследников, а у 21го недоглядел, не поменял. И тогда, если у базового функция не абстрактная, то 21й наследник будет использовать именно её, а не свою специфическую. Что и есть ошибка, которая может проявиться сразу, а может и через год.
Представь себе бывает нужно поменять. Поменяешь у базового класса, поменяешь у 20ти наследников, а у 21го недоглядел, не поменял. И тогда, если у базового функция не абстрактная, то 21й наследник будет использовать именно её, а не свою специфическую. Что и есть ошибка, которая может проявиться сразу, а может и через год.
Это говорит о хреновом проектировании.
Потом ты звонишь всем клиентам и просишь поменять сигнатуры функций в клиентском коде ? :-)
NEW 20.09.09 10:49
Спасибо, о Гуру ! :-)
Хоть вся твоя проблема кажется надуманной, но можно сделать вот так.
class superclass{
virtual void myfun(int n, bool b)=0;
};
class A:superclass{};
С помощью компилятора найдешь все классы.
в ответ anly 20.09.09 08:46
В ответ на:
Так и быть объясню вам, далеко от плюсов отошедших.
Так и быть объясню вам, далеко от плюсов отошедших.
Спасибо, о Гуру ! :-)
В ответ на:
Прошло сто лет и надо добавить параметр в функцию. Этот параметр обрабатывается только в функции одного из наследников (которого я здесь даже не показал), функция базового класса(А) новый параметр просто игнорирует, класса С - тоже.
Прошло сто лет и надо добавить параметр в функцию. Этот параметр обрабатывается только в функции одного из наследников (которого я здесь даже не показал), функция базового класса(А) новый параметр просто игнорирует, класса С - тоже.
Хоть вся твоя проблема кажется надуманной, но можно сделать вот так.
class superclass{
virtual void myfun(int n, bool b)=0;
};
class A:superclass{};
С помощью компилятора найдешь все классы.
NEW 20.09.09 12:55
в ответ anly 20.09.09 08:46
везёт вам
------
Не нам везет - куЁм свое везение сами. Частенько это стоит большего количества
работы...
может проявиться только после изменений
-----
А после изменений тестировать не надо?
ошибка !!!!!
-----
Это не ошибка - это именно то, что ты написал.
И с подобными описками тоже можно бороться. Например, можно, изначально,
еще в правилах кодинга, задать требование об отсутствии использования встроенных
типов в качестве параметров и тогда это выглядит так:
class MyFuncParam { ... }
class A
{
virtual void myfun(MyFuncParam& n);
}
...etc...
тут любые изменения не затрагивают базовый код, независимо от изменений содержимого
MyFuncParam.
------
Не нам везет - куЁм свое везение сами. Частенько это стоит большего количества
работы...
может проявиться только после изменений
-----
А после изменений тестировать не надо?
ошибка !!!!!
-----
Это не ошибка - это именно то, что ты написал.
И с подобными описками тоже можно бороться. Например, можно, изначально,
еще в правилах кодинга, задать требование об отсутствии использования встроенных
типов в качестве параметров и тогда это выглядит так:
class MyFuncParam { ... }
class A
{
virtual void myfun(MyFuncParam& n);
}
...etc...
тут любые изменения не затрагивают базовый код, независимо от изменений содержимого
MyFuncParam.
NEW 20.09.09 13:05
в ответ Chipolino 20.09.09 10:49
С помощью компилятора найдешь все классы.
-----
Что-то меня сомнения берут. Бо, чистую виртуальную функцию обязан определять _хотя бы один_ из потомков. Как только один определит - ситуация становится эквивалентной первичной - может быть опущена в потомках.
-----
Что-то меня сомнения берут. Бо, чистую виртуальную функцию обязан определять _хотя бы один_ из потомков. Как только один определит - ситуация становится эквивалентной первичной - может быть опущена в потомках.
NEW 20.09.09 13:22
В отличии от C++ питон выкинет исключение, а не дёрнет подходящий метод из цепочки наследования сверху. Которой и не будет вовсе. Просто, надо писать на питоне, а не на C++ с синтаксисом питона.
Наследование применяется в двух случаях - для создания функциональности в предке, чтобы не дублировать её в потомке и для реализации полиморфизма: имея ссылку или указатель на базовый класс, вызывать методы определённые в потомке. Для первой цели в питоне применяют наследование, для второй - нет.
Полиморфизм реализуют так:
В ответ на:
Представь себе бывает нужно поменять. Поменяешь у базового класса, поменяешь у 20ти наследников, а у 21го недоглядел, не поменял. И тогда, если у базового функция не абстрактная, то 21й наследник будет использовать именно её, а не свою специфическую. Что и есть ошибка, которая может проявиться сразу, а может и через год.
Представь себе бывает нужно поменять. Поменяешь у базового класса, поменяешь у 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 - средство синхронизации и бэкапа файлов.
NEW 20.09.09 13:27
в ответ anly 17.09.09 22:44
писать надо короткоги ясно - не должно быть ситуаций, когда один класс делает работу всего приложения через стотыщь мильонов функций-членов, или одна функция на 10 тыс строк выполняет всю работу определенной подсистемы. Тут важно грамотное проектирование, и желательно сразу с поддержкой unit-тестов...
Очень хорошой в смысле писания "правильного" кода является книжка Code Complete - там много полезных советов на такие темы.
унаследованный код тоже можно рефакторить, избавляться от дублирования кода, разбивать длиные функции на меньшие, например, центральная функция является точкой входа, и определяет логику вычислений, но из нее зовуться только другие функции, которые и выполняют всю работу.
Очень хорошой в смысле писания "правильного" кода является книжка Code Complete - там много полезных советов на такие темы.
унаследованный код тоже можно рефакторить, избавляться от дублирования кода, разбивать длиные функции на меньшие, например, центральная функция является точкой входа, и определяет логику вычислений, но из нее зовуться только другие функции, которые и выполняют всю работу.
NEW 20.09.09 14:24
Если в потомке, определена, то в потомках потомка конечно не надо.
Но в его примере все наследуют от одного 'A'.
в ответ Murr 20.09.09 13:05
В ответ на:
Что-то меня сомнения берут. Бо, чистую виртуальную функцию обязан определять _хотя бы один_ из потомков. Как только один определит - ситуация становится эквивалентной первичной - может быть опущена в потомках.
Что-то меня сомнения берут. Бо, чистую виртуальную функцию обязан определять _хотя бы один_ из потомков. Как только один определит - ситуация становится эквивалентной первичной - может быть опущена в потомках.
Если в потомке, определена, то в потомках потомка конечно не надо.
Но в его примере все наследуют от одного 'A'.
NEW 20.09.09 14:41
Виртуальность хорошая вещь, но использовать её нужно только там где без нее не обойтись. И в шею гнать надо программистов которые 'на всякий случай' делают каждую функцию виртуальной. А питон сразу делает это, даже тебя не спросит...
В ответ на:
Это говорит о хреновом проектировании.
дык, а я о чем говорю! Но выбирать уже не приходится. Ты пришел на работу и у тебя есть хреново спроектированная программа. Те люди которые её писали уже здесь не работают. И твоя задача перепроектировать её получше. Эту задачу вообщето тебе начальство не ставит, начальству надо чтоб притензий от заказчиков не было и не более. Но тебе в этом дерьме ковыряться и поэтому ты сам хочешь навести там порядок, на свой страх и риск. Так вот каждая виртуальная функция усложняет эту задачу. Т.к. ошибку, которую я привёл в примере, можно обнаружить только в результате тестирования. А протестировать огромную программу не всегда возможно. Просто хотя бы из за отсутствия времени. Там где нет
виртуальности - проще, т.к. об ошибке сообщит компилятор, и ты никуда не денешся - подправиш. Это говорит о хреновом проектировании.
Виртуальность хорошая вещь, но использовать её нужно только там где без нее не обойтись. И в шею гнать надо программистов которые 'на всякий случай' делают каждую функцию виртуальной. А питон сразу делает это, даже тебя не спросит...
В ответ на:
Потом ты звонишь всем клиентам и просишь поменять сигнатуры функций в клиентском коде ? :-)
не понял. клиенты - простые пользователи и ни о чём вышеописанном не подозревают.Потом ты звонишь всем клиентам и просишь поменять сигнатуры функций в клиентском коде ? :-)
Проклят нарушающий межи ближнего своего (Втор.27:17)
NEW 20.09.09 15:01
Unittest входит в базовую библиотеку питона, юнит-тестирование выявляет эту ошибку (в С++, кстати, нет). Проверка же типов / сигнатур в рантайме - особенность динамических языков.
в ответ anly 20.09.09 14:49
В ответ на:
это тоже ошибка выполнения, которая обнаруживается только тестированием.
это тоже ошибка выполнения, которая обнаруживается только тестированием.
Unittest входит в базовую библиотеку питона, юнит-тестирование выявляет эту ошибку (в С++, кстати, нет). Проверка же типов / сигнатур в рантайме - особенность динамических языков.
Dropbox - средство синхронизации и бэкапа файлов.
NEW 20.09.09 15:13
Разве этот тест не сам программист должен написать? Разве всегда возможно написать тест который обнаружит любые ошибки? А тест для теста тоже надо писать? ведь и в тесте может ошибка оказаться. Я не против юниттестов, наверняка очень хорошая практика, но не панацея, 100процентной гарантии нет.
в ответ voxel3d 20.09.09 15:01
В ответ на:
Unittest входит в базовую библиотеку питона, юнит-тестирование выявляет эту ошибку (в С++, кстати, нет).
для меня, как незнатока питона, это звучит несколько "волшебно". Т.е. юниттест "чудестным" образом обнаружит ошибку. Unittest входит в базовую библиотеку питона, юнит-тестирование выявляет эту ошибку (в С++, кстати, нет).
Разве этот тест не сам программист должен написать? Разве всегда возможно написать тест который обнаружит любые ошибки? А тест для теста тоже надо писать? ведь и в тесте может ошибка оказаться. Я не против юниттестов, наверняка очень хорошая практика, но не панацея, 100процентной гарантии нет.
Проклят нарушающий межи ближнего своего (Втор.27:17)
NEW 20.09.09 15:24
Это не "любая ошибка". Программа 100% валится на попытке вызова метода - соответственно, независимо от того, что именно будет проверять юнит-тест, ошибка будет выявлена.
Тесты, да, пишет сам программист.
Это у тебя с твоим вариантом полиморфизма нет, а в тут есть.
Тесты, да, пишет сам программист.
В ответ на:
Я не против юниттестов, наверняка очень хорошая практика, но не панацея, 100процентной гарантии нет.
Я не против юниттестов, наверняка очень хорошая практика, но не панацея, 100процентной гарантии нет.
Это у тебя с твоим вариантом полиморфизма нет, а в тут есть.

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