Зачем создавать два файла (className.h и className.cpp) для класса? [dубликат]

Дамп всех баз данных со всеми таблицами, но пропустите определенные таблицы

на github: https://github.com/rubo77/mysql-backup.sh/blob/master/mysql-backup.sh

#!/bin/bash # mysql-backup.sh if [ -z "$1" ] ; then echo echo "ERROR: root password Parameter missing." exit fi DB_host=localhost MYSQL_USER=root MYSQL_PASS=$1 MYSQL_CONN="-u${MYSQL_USER} -p${MYSQL_PASS}" #MYSQL_CONN="" BACKUP_DIR=/backup/mysql/ mkdir $BACKUP_DIR -p MYSQLPATH=/var/lib/mysql/ IGNORE="database1.table1, database1.table2, database2.table1," # strpos $1 $2 [$3] # strpos haystack needle [optional offset of an input string] strpos() { local str=${1} local offset=${3} if [ -n "${offset}" ]; then str=`substr "${str}" ${offset}` else offset=0 fi str=${str/${2}*/} if [ "${#str}" -eq "${#1}" ]; then return 0 fi echo $((${#str}+${offset})) } cd $MYSQLPATH for i in */; do if [ $i != 'performance_schema/' ] ; then DB=`basename "$i"` #echo "backup $DB->$BACKUP_DIR$DB.sql.lzo" mysqlcheck "$DB" $MYSQL_CONN --silent --auto-repair >/tmp/tmp_grep_mysql-backup grep -E -B1 "note|warning|support|auto_increment|required|locks" /tmp/tmp_grep_mysql-backup>/tmp/tmp_grep_mysql-backup_not grep -v "$(cat /tmp/tmp_grep_mysql-backup_not)" /tmp/tmp_grep_mysql-backup tbl_count=0 for t in $(mysql -NBA -h $DB_host $MYSQL_CONN -D $DB -e 'show tables') do found=$(strpos "$IGNORE" "$DB"."$t,") if [ "$found" == "" ] ; then echo "DUMPING TABLE: $DB.$t" mysqldump -h $DB_host $MYSQL_CONN $DB $t --events --skip-lock-tables | lzop -3 -f -o $BACKUP_DIR/$DB.$t.sql.lzo tbl_count=$(( tbl_count + 1 )) fi done echo "$tbl_count tables dumped from database '$DB' into dir=$BACKUP_DIR" fi done

С небольшой помощью https://github.com/rubo77/mysql-backup.sh/blob/master/mysql-backup.sh

Он использует lzop, который намного быстрее, см. http: //pokecraft.first-world.info/wiki/Quick_Benchmark: _Gzip_vs_Bzip2_vs_LZMA_vs_XZ_vs_LZ4_vs_LZO

91
задан Marius 20 August 2009 в 15:18
поделиться

13 ответов

Кажется, вы спрашиваете о разделении определений из объявлений, хотя есть и другие файлы для заголовков.

Ответ заключается в том, что C ++ не нуждается в этом. Если вы помечаете все inline (которое в любом случае автоматическое для функций-членов, определенных в определении класса), тогда нет необходимости в разделении. Вы можете просто определить все в файлах заголовков.

Причинами, которые вы могли бы захотеть для разделения, являются:

  1. Улучшить время сборки.
  2. Чтобы ссылаться на код без источника для определений.
  3. Чтобы не маркировать все «inline».

Если ваш более общий вопрос, «Почему C ++ не идентичен Java?», то я должен спросить: «Почему вы пишете C ++ вместо Java?» ; -p

. Более серьезно, однако, причина в том, что компилятор C ++ не может просто перейти в другую единицу перевода и выяснить, как использовать его символы так, как может и делает javac. Файл заголовка необходим, чтобы объявить компилятору, что он может ожидать в момент ссылки.

Итак, #include - это прямая текстовая подстановка. Если вы определяете все в заголовочных файлах, препроцессор заканчивает создание огромной копии и вставки каждого исходного файла в вашем проекте и подачи этого в компилятор. Тот факт, что стандарт C ++ был ратифицирован в 1998 году, не имеет к этому никакого отношения, это тот факт, что среда компиляции для C ++ основана так тесно на C.

Преобразование моих комментариев для ответа на ваши последующие комментарии, Вопрос:

Как компилятор находит файл .cpp с кодом в нем

Это не так, по крайней мере, не в то время, когда он компилирует код, который использовал файл заголовка. Функции, с которыми вы связываетесь, даже не нужно писать, не говоря уже о компиляторе, зная, какой файл .cpp они будут находиться. Все, что должен знать код вызова во время компиляции выражается в объявлении функции. Во время ссылки вы предоставите список файлов .o , или статических или динамических библиотек, и заголовок в действительности является обещанием, что определения функций будут там где-то.

84
ответ дан Steve Jessop 16 August 2018 в 00:57
поделиться
  • 1
    Чтобы добавить к & quot; Причины, которые вы хотите разделить, следующие: & quot; & Амп; Я считаю, что наиболее важной функцией файлов заголовков является: Отделить дизайн структуры кода от реализации, потому что: A. Когда вы попадаете в действительно сложные структуры, которые включают в себя множество объектов, гораздо проще просеивать файлы заголовков и помнить, как они работают вместе, дополненный комментариями вашего заголовка. B. Пусть один человек не заботится о том, чтобы определить всю структуру объекта, а кто-то другой заботится о реализации, он держит вещи организованными. По всей видимости, это делает сложный код более читаемым. – Andres Canella 12 July 2012 в 17:19
  • 2
    Проще всего я могу думать о полезности разделения файлов заголовков и cpp, чтобы разделить интерфейс и реализации, который действительно помогает для средних / больших проектов. – darth_coder 19 March 2015 в 08:09
  • 3
    Я намеревался включить в (2), «ссылку на код без определения». Хорошо, так что вы все равно можете получить доступ к git-репо с определениями, но дело в том, что вы можете скомпилировать свой код отдельно от реализаций его зависимостей, а затем связать. Если буквально все, что вам нужно, - это разделить интерфейс / реализацию на разные файлы, не заботясь о том, чтобы строить отдельно, тогда вы могли бы сделать это, просто имея foo_interface.h, включая foo_implementation.h. – Steve Jessop 19 March 2015 в 10:02
  • 4
    @AndresCanella Нет, нет. Это делает чтение и поддержание не собственного кода кошмаром. Чтобы полностью понять, что что-то делает в коде, вам нужно перепрыгнуть через 2n-файлы вместо n файлов. Это просто не нота Big-Oh, 2n делает большую разницу по сравнению с только n. – Błażej Michalik 10 April 2016 в 12:37
  • 5
    Во-вторых, это ложь, которая помогает. например, проверьте источник minix, так сложно следить за тем, где он начинается, где передается элемент управления, где вещи объявлены / определены. Если он был создан через разделенные динамические модули, он был бы удобоваримым, если бы он понял одно, а затем прыгнул в модуль зависимости. вместо этого вам нужно следить за заголовками, и это делает чтение любого кода, написанного таким образом адом. напротив, nodejs дает понять, откуда происходит без каких-либо ifdefs, и вы можете легко определить, откуда. – Dmitry 16 August 2016 в 18:01

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

Это действительно проблема с областью.

3
ответ дан Alex Rodrigues 16 August 2018 в 00:57
поделиться

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

1
ответ дан Community 16 August 2018 в 00:57
поделиться

C ++ был разработан для добавления современных возможностей языка программирования в инфраструктуру C без лишнего изменения чего-либо о C, который не был конкретно о самом языке.

Да, на этом этапе (через 10 лет после первый стандарт C ++ и спустя 20 лет после того, как он начал серьезно расти в использовании), легко спросить, почему у него нет надлежащей модульной системы. Очевидно, что любой новый язык, который разрабатывается сегодня, не будет работать, как C ++. Но это не относится к C ++.

Точка C ++ должна быть эволюционной, гладкой продолжением существующей практики, только добавляя новые возможности без (слишком часто) нарушения вещей, которые адекватно работают для пользователя community

Это означает, что это делает некоторые вещи сложнее (особенно для людей, начинающих новый проект), а некоторые вещи проще (особенно для тех, кто поддерживает существующий код), чем другие языки.

Вместо того, чтобы ожидать, что C ++ превратится в C # (что было бы бессмысленно, поскольку у нас уже есть C #), почему бы просто не выбрать подходящий инструмент для работы? Я сам пытаюсь написать важные фрагменты новой функциональности на современном языке (я использую C #), и у меня есть большое количество существующих C ++, которые я храню на C ++, потому что не было бы реальной ценности при повторной записи его все. В любом случае, они очень хорошо интегрируются, поэтому в значительной степени безболезненно.

4
ответ дан Daniel Earwicker 16 August 2018 в 00:57
поделиться
  • 1
    Как вы интегрируете C # и C ++? Через COM? – Peter Mortensen 20 August 2009 в 15:23
  • 2
    Существует три основных способа: «лучший», зависит от вашего существующего кода. Я использовал все три. Тот, который я использую больше всего, это COM, потому что мой существующий код уже был разработан вокруг него, поэтому он практически бесшовна, отлично работает для меня. В некоторых нечетных местах я использую C ++ / CLI, который обеспечивает невероятно плавную интеграцию для любой ситуации, когда у вас еще нет COM-интерфейсов (и вы можете предпочесть использовать существующие COM-интерфейсы, даже если у вас их есть). Наконец, есть p / invoke, который в основном позволяет вам вызывать любую C-подобную функцию, открытую из DLL, поэтому вы можете напрямую вызвать любой Win32 API из C #. – Daniel Earwicker 20 August 2009 в 16:58

C ++ был ратифицирован в 1998 году, так почему он спроектирован таким образом? Какие преимущества имеет отдельный файл заголовка?

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

1
ответ дан Diaa Sami 16 August 2018 в 00:57
поделиться

Первое преимущество: если у вас нет файлов заголовков, вам придется включать исходные файлы в другие исходные файлы.

Второе преимущество: он позволяет обмениваться интерфейсами без совместного использования кода между разными единицами (разные разработчики, команды, компании и т. Д.) [ ! d1]

11
ответ дан erelender 16 August 2018 в 00:57
поделиться
  • 1
    Вы подразумеваете, что, например, в C # 'вам придется включать исходные файлы в другие исходные файлы? Потому что, очевидно, нет. Для второго преимущества, я думаю, это слишком зависит от языка: вы не будете использовать файлы .h в, например. Delphi – Vlagged 20 August 2009 в 14:01
  • 2
    Вы все равно должны перекомпилировать весь проект, так же как и первое преимущество? – Marius 20 August 2009 в 14:06
  • 3
    хорошо, но я не думаю, что языковая функция. Более практично иметь дело с декларацией C перед определением & quot; проблема & quot ;. Это как кто-то знаменитый высказывание «это не ошибка, а функция». :) – neuro 20 August 2009 в 14:14
  • 4
    @Marius: Да, это действительно так. Связывание всего проекта отличается от компиляции и увязки всего проекта. По мере увеличения количества файлов в проекте компиляция всех из них становится очень раздражающей. @Vlagged: Вы правы, но я не сравнивал c ++ с другим языком. Я сравнивал использование только исходных файлов с использованием файлов заголовков и заголовков. – erelender 20 August 2009 в 14:17
  • 5
    C # не содержит исходные файлы в других, но вам все равно приходится ссылаться на модули - и это заставляет компилятор извлекать исходные файлы (или отражать их в двоичном формате) для анализа символов, используемых вашим кодом. – gbjbaanb 20 August 2009 в 14:18

Некоторые люди считают заголовочные файлы преимуществом:

  • Утверждается, что он включает / обеспечивает / позволяет разделять интерфейс и реализацию, но обычно это не так. Заголовочные файлы полны деталей реализации (например, переменные-члены класса должны быть указаны в заголовке, даже если они не являются частью общедоступного интерфейса), а функции могут и часто задаются inline в объявление класса в заголовке, снова разрушая это разделение.
  • Иногда говорят, что улучшать время компиляции, потому что каждая единица перевода может обрабатываться независимо. И все же C ++ - это, вероятно, самый медленный язык, который существует, когда дело доходит до времени компиляции. Одной из причин является много многократных включений одного и того же заголовка.

В конечном итоге система заголовков является артефактом 70-х годов, когда C был спроектирован. В то время у компьютеров было очень мало памяти, и сохранение всего модуля в памяти просто не было вариантом. Компилятор должен был начать читать файл вверху, а затем продолжить линейно через исходный код. Механизм заголовка позволяет это. Компилятор не должен учитывать другие единицы перевода, он просто должен прочитать код сверху вниз.

И C ++ сохранил эту систему для обратной совместимости.

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

Однако одно из предложений для C ++ 0x состояло в том, чтобы добавить правильную систему модулей, позволяя компилировать код, подобный .NET или Java, в более крупные модули, все в одном и без заголовков. Это предложение не делало сокращения в C ++ 0x, но я считаю, что он все еще находится в категории «мы бы хотели сделать это позже». Возможно, в TR2 или аналогичном.

44
ответ дан jalf 16 August 2018 в 00:57
поделиться

Ну, C ++ был ратифицирован в 1998 году, но он использовался намного дольше, чем это, и ратификация заключалась в основном в определении текущего использования, а не наложении структуры. И поскольку C ++ был основан на C, а C имеет заголовочные файлы, C ++ тоже имеет их.

Основной причиной заголовочных файлов является включение отдельной компиляции файлов и минимизация зависимостей.

Скажем, у меня есть foo.cpp, и я хочу использовать код из файлов bar.h / bar.cpp.

Я могу # включить «bar.h» в foo.cpp, а затем запрограммировать и скомпилировать foo.cpp, даже если bar.cpp не существует. Файл заголовка выступает в качестве обещания компилятору, что классы / функции в bar.h будут существовать во время выполнения, и у него есть все, что ему нужно знать.

Конечно, если функции в bar.h не имеют тел, когда я пытаюсь связать свою программу, тогда она не будет связываться, и я получу ошибку.

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

Другим является то, что если вы измените реализацию своего кода в файле * .cpp, но не изменяете заголовок вообще, вам нужно только скомпилировать * .cpp-файл, а не все, что его использует , Конечно, если вы введете много изменений в заголовочный файл, это станет менее полезным.

1
ответ дан Mark Krenitsky 16 August 2018 в 00:57
поделиться

К моему (ограниченному - я вообще не разработчик C), это связано с C. Помните, что C не знает, какие классы или пространства имен есть, это всего лишь одна длинная программа.

Например, следующее должно приводить к ошибке компилятора:

  void SomeFunction () {SomeOtherFunction ();  } void SomeOtherFunction () {printf («Что?»);  }  

Ошибка должна заключаться в том, что «SomeOtherFunction не объявлен», потому что вы вызываете ее перед ее объявлением. Одним из способов его устранения является перемещение SomeOtherFunction над SomeFunction. Другой подход заключается в том, чтобы сначала объявить подпись функции:

  void SomeOtherFunction ();  void SomeFunction () {SomeOtherFunction ();  } void SomeOtherFunction () {printf («Что?»);  }  

Это позволяет компилятору узнать: посмотрите где-нибудь в коде, есть функция SomeOtherFunction, которая возвращает void и не принимает никаких параметров. Итак, если вы используете код, который пытается вызвать SomeOtherFunction, не паникуйте и вместо этого ищите его.

Теперь представьте, что у вас есть SomeFunction и SomeOtherFunction в двух разных файлах .c. Затем вам нужно включить # SomeOther.c в Some.c. Теперь добавьте некоторые «частные» функции в SomeOther.c. Поскольку C не знает частных функций, эта функция будет доступна и в Some.c.

Здесь находятся файлы .h. Они определяют все функции (и переменные), которые вы хотите " Экспортировать 'из файла .c, доступ к которому можно получить в других файлах .c. Таким образом, вы получаете что-то вроде области Public / Private. Кроме того, вы можете предоставить этот файл .h для других людей, не передавая свой исходный код - файлы .h также работают с скомпилированными .lib-файлами.

Таким образом, основная причина действительно для удобства, для источника защиты кода и иметь немного развязки между частями вашего приложения.

Это было C, хотя. В C ++ введены классы и частные / общедоступные модификаторы, поэтому, хотя вы все еще можете спросить, нужны ли они, C ++ AFAIK по-прежнему требует объявления функций перед их использованием. Кроме того, многие разработчики C ++ являются или являются C devleopers, а также используют свои концепции и привычки для C ++ - зачем менять то, что не сломано?

23
ответ дан Michael Stum 16 August 2018 в 00:57
поделиться
  • 1
    Почему компилятор не может пропустить код и найти все определения функций? Это похоже на то, что было бы довольно легко запрограммировать в компилятор. – Marius 20 August 2009 в 14:16
  • 2
    Если у вас есть источник, которого у вас часто нет. Скомпилированный C ++ - это действительно машинный код с достаточно дополнительной информацией для загрузки и связывания кода. Затем вы указываете CPU в точке входа и позволяете ему работать. Это принципиально отличается от Java или C #, где код компилируется в промежуточный байт-код, содержащий метаданные в его содержимом. – DevSolar 20 August 2009 в 14:27
  • 3
    Я предполагаю, что в 1972 году это могло быть довольно дорогостоящей операцией для компилятора. – Michael Stum♦ 20 August 2009 в 14:28
  • 4
    Именно то, что сказал Майкл Стам. Когда это поведение было определено, единственное, что может быть практически реализовано, - это линейное сканирование через единицу перевода. – jalf 20 August 2009 в 14:40
  • 5
    Yup - компиляция на 16-ти готическом носителе с ленточным запоминающим устройством является нетривиальной. – MSalters 20 August 2009 в 15:10

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

  #ifndef MY_HEADER_SWEET_GUARDIAN #define MY_HEADER_SWEET_GUARDIAN // [...] //  мой заголовок // [...] #endif // MY_HEADER_SWEET_GUARDIAN  

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

So , Я думаю, что когда C был создан, проблемы с форвардным объявлением были недооценены, и теперь, когда мы используем язык высокого уровня, такой как C ++, мы имеем дело с такими вещами.

Еще одно бремя для нас, бедных пользователей C ++ ...

1
ответ дан neuro 16 August 2018 в 00:57
поделиться

C ++ делает это так, потому что C сделал это так, поэтому реальный вопрос - почему C сделал это так? Википедия немного говорит об этом.

Новые скомпилированные языки (такие как Java, C #) не используют форвардные объявления; идентификаторы автоматически распознаются из исходных файлов и считываются непосредственно из динамических символов библиотеки. Это означает, что файлы заголовков не нужны.

69
ответ дан ongle 16 August 2018 в 00:57
поделиться
  • 1
    +1 Захватывает гвоздь на голове. Это действительно не требует подробного объяснения. – MSalters 20 August 2009 в 15:01
  • 2
    Это не поразило мой гвоздь по голове :( Мне все еще нужно искать, почему C ++ должен использовать форвардные объявления и почему он не может распознавать идентификаторы из исходных файлов и читать напрямую из динамических символов библиотеки и почему C ++ сделал это так просто потому, что C сделал это так: p – Alexander Taylor 1 August 2015 в 00:11
  • 3
    И вы лучший программист за то, что сделали это @AlexanderTaylor :) – ongle 2 August 2015 в 02:13

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

0
ответ дан Tadeusz Kopec 16 August 2018 в 00:57
поделиться

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

Чтобы компенсировать это ограничение, C и C ++ допускают объявления и эти объявления могут быть включены в модули, которые используют их с помощью директивы #include препроцессора.

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

Причина того, что информация привязки, не включаемая в вывод компилятора, проста: она не нужна во время выполнения (проверка любого типа происходит во время компиляции). Это просто потеряло бы пространство. Помните, что C / C ++ происходит с того момента, когда размер исполняемого файла или библиотеки имеет значение совсем немного.

4
ответ дан VoidPointer 16 August 2018 в 00:57
поделиться
Другие вопросы по тегам:

Похожие вопросы: