Это зависит от того, где вы находитесь в цикле разработки, но иногда, когда вы делаете набросок алгоритма, вы хотите создать абстракцию о сложных блоках, не выполняя их сразу.
def full_algo():
init_stuff()
process_stuff()
...
Вы знаете, как это init_stuff
будет работать, это довольно просто в вашей голове, но вам это на самом деле не нужно, поэтому вы объявляете это пустой функцией. Это позволит вашему коду компилироваться и запускаться, не беспокоясь о кровавых деталях.
Другое использование для выпущенных приложений - при использовании наследования. Предположим, у вас есть большой класс, который определяет поведение кода, специфичного для платформы. Вы можете получить логику, подобную этой:
init_filesystem();
access_files();
release_filesystem();
Этот код будет работать на многих платформах, но некоторые платформы могут не нуждаться в инициализации файловой системы. Тогда ваше наследование будет выглядеть так (виртуальный с = 0 в C ++ означает, что производные классы ДОЛЖНЫ реализовывать эти методы):
class FileSystem{
virtual void init_filesystem() = 0;
virtual void access_files() = 0;
virtual void release_filesystem() = 0;
};
Тогда конкретная реализация этого класса (интерфейса) может ничего не делать для некоторых из этих методов. Кроме того, базовый класс может объявлять пустые методы для init / release вместо объявления их виртуальными.
Наконец (и позорно), иногда вы поддерживаете очень старое приложение. Вы боитесь, что удаление методов сломает вещи. Это происходит, когда у вас сложное наследование, которое неправильно понимается, или когда у вас много указателей на функции (обратные вызовы). Вы просто удаляете код внутри них, чтобы они все равно вызывались, ничего не нарушая.