Декларация и реализация функций - PullRequest
7 голосов
/ 08 декабря 2010

По словам моего учителя, это плохая практика - писать пользовательские функции, такие как:

int DoubleNumber(int Number)
{
    return Number * 2;
}

int main()
{
    cout << DoubleNumber(8);
}

Вместо этого он говорит всегда использовать предварительные объявления, даже если функции немне не нужны никакие знания друг о друге:

int DoubleNumber(int Number); // Forward declaration.

int main()
{
    cout << DoubleNumber(8);
}

int DoubleNumber(int Number) // Implementation.
{
    return Number * 2;
}

Я нахожу это особенно странным, поскольку он намеревался сказать нам, насколько важно, чтобы предварительное объявление и реализация были точно .то же самое, или вы получите ошибки.Если это так грандиозно, почему бы просто не поставить все это выше main()?

Итак, действительно ли это плохая практика объявлять и реализовывать одновременно?Это вообще имеет значение?

Ответы [ 9 ]

14 голосов
/ 08 декабря 2010

Если вы не объявляете предварительные объявления («прототипы»), то вам нужно убедиться, что все ваши функции выполняются перед любыми функциями, которые зависят от них, то есть в обратном порядке графа вызовов. Это хорошо для простого примера, как указано выше, но это полная боль для чего-то более реалистичного (а в некоторых случаях невозможного, если в графе вызовов есть какие-либо циклы).

6 голосов
/ 08 декабря 2010

Я думаю, что ваш учитель - старый программист на Си.

Если вы написали программу на С без предварительных объявлений и одну функцию, вызванную другой функцией, объявленной позже в файле (или в другом модуле компиляции), компиляторне будет жаловаться, но молча притворяется, что знает, каким должен быть прототип.

Отладка ужасна, если вы не знаете, правильно ли ваш компилятор передает аргументы.Поэтому это была хорошая оборонительная политика - всегда объявлять все функции;по крайней мере, компилятор мог вызвать ошибку, если объявление не соответствовало реализации.

Компиляторы и инструментальные средства C стали лучше (я надеюсь).Вызов неизвестной функции все еще не является ошибкой, но, например, GCC достаточно любезен, чтобы предупреждать по умолчанию.

Но в C ++ нельзя вызывать функцию, которая не была объявлена ​​или определена.Следовательно, программисты на C ++ не сильно беспокоятся о предварительных декларациях.

6 голосов
/ 08 декабря 2010

Политика вашего учителя ужасна, ИМХО.Используйте предварительные декларации только тогда, когда они действительно необходимы.Таким образом, их присутствие демонстрирует их необходимость, что дает читателю полезную документацию (т. Е. Между функциями может быть взаимная рекурсия).Конечно, вам нужны предварительные объявления в заголовочных файлах;вот для чего они.

4 голосов
/ 08 декабря 2010

В моем первом уроке программирования учитель также подчеркивал этот момент. Я не совсем уверен, что такой простой случай полезен в реальном программном обеспечении.

Однако, подготавливает вас к использованию заголовочных файлов, если вы еще не рассмотрели это. В типичном случае у вас будет заголовочный файл custom-math.h и исходный файл custom-math.cpp, где custom-math.h содержит предварительную декларацию и custom-math.cpp реализацию. Это может значительно увеличить время компиляции при внесении изменений в реализации функций только в больших проектах. Это также удобный способ разбить вашу программу на «логические» группы функций и / или классов.

Если вы собираетесь поместить другие функции в тот же файл, что и main(), то, что вы делаете, вероятно, зависит от ваших личных предпочтений . Некоторые люди предпочитают иметь main() близко к вершине, чтобы сразу перейти к логике программы. В этом случае, вперед объявите ваши функции.

3 голосов
/ 08 декабря 2010

Карл Кнектхел пишет: «Используйте предварительные объявления только тогда, когда они действительно необходимы. Таким образом, их присутствие демонстрирует их необходимость, что дает читателю полезную документацию (т. Е. Между функциями может быть взаимная рекурсия)». и имхо это здравый совет.

Оли Чарльзуорт говорит о "полной боли" для упорядочивания функций, чтобы их можно было вызывать без предварительных объявлений. Это не мой опыт, и я не могу себе представить, как эта боль / проблема решается. Я подозреваю, что PEBCAK проблема там.

Практика использования предварительных объявлений для всех функций не избавит вас от проблем PEBCAK, но они привносят излишнюю работу по сопровождению и лишний код, к которому они относятся, и делают более неясным, какие функции действительно нуждаются в предварительных объявлениях.

Если вы попадаете в точку, где предварительные объявления могут помочь сразу увидеть сигнатуры функций, когда их переводят в какой-то очень простой редактор, тогда нужно выполнить два действия: (1) рефакторинг кода и ( 2) переход на лучший редактор.

Приветствия & hth.,

2 голосов
/ 08 декабря 2010

Спросите своего учителя о , почему он рекомендует это;) В любом случае, на мой взгляд, это неплохая практика, и в большинстве случаев это даже не имеет значения. Самым большим преимуществом объявления всех функций заранее является то, что у вас есть общее представление о том, что делает код.

1 голос
/ 08 декабря 2010

Общие правила редко бывают правильными. Публичный API, который вы обычно выставляете через прототипы в заголовочном файле. Остальные функции, вероятно, будут находиться в анонимном пространстве имен в файле cpp. Если они вызываются несколько раз в реализации, имеет смысл предоставить прототипы наверху, иначе каждая функция, использующая их, должна будет предоставлять прототипы перед вызовом функций. В то же время, если какая-то функция используется в файле cpp несколько раз, это может указывать на то, что она достаточно универсальна, чтобы ее можно было перенести в общий API. Если функции не используются повсеместно, лучше предоставить им как можно более ограниченное воздействие, т. Е. Объявлять и определять их близко к месту, откуда они вызываются.

1 голос
/ 08 декабря 2010

Традиционно вы будете помещать все свои прототипы в заголовочный файл, чтобы они могли использоваться другими исходными файлами - или, по крайней мере, вы поместите те, которые вы хотите показать, в файл .h.

Что касается кода, в котором нет необходимости, есть что сказать, чтобы поместить все ваши объявления на уровне файлов вверху (переменные и функции), потому что это означает, что вы можете перемещать функции по своему усмотрению и не беспокоиться Это. Не говоря уже о том, что я сразу вижу каждую функцию в файле. Но что-то вроде:

void Func1() { ... }
...
void Func2() { ... }
...
void Func3() { ... }
...
int main() { Func1(); Func2(); Func3(); return 0; }

То есть, то есть ряд несвязанных функций, вызываемых main (), является очень распространенным файлом, и вполне разумно отказаться от объявления.

0 голосов
/ 08 декабря 2010

Лично мне нравится только перенаправлять объявление всего, о чем клиентскому коду нужно знать (т.е. в заголовке класса).Все, что является локальным для реализации класса (например, вспомогательные функции), должно быть определено до использования.

Конечно, в конце дня, по большей части, это сводится либо к личным предпочтениям, либо к кодированиюСтандарт, которому следует ваш проект.

...