Во-первых, вы не должны помещать в заголовки ничего, что не должно быть видимым для любого другого файла, кроме того, который в этом нуждается. Затем давайте определим то, что нам нужно ниже.
Бюро переводов
Единица трансляции - это текущий компилируемый код и весь код, включенный в него прямо или косвенно. Одна единица перевода переводится в один файл .o / .obj.
Программа
Это все ваши файлы .o / .obj, связанные вместе в один двоичный файл, который может быть выполнен для формирования процесса.
Каковы основные моменты использования разных единиц перевода?
- Уменьшите зависимости, чтобы при изменении одного метода одного класса вам не приходилось перекомпилировать весь код вашей программы, а только затронутую единицу трансляции. An
- Уменьшите возможные конфликты имен, используя локальные имена единиц перевода, которые не видны другим единицам перевода при их связывании.
Как теперь разделить код на разные единицы перевода? Ответа на этот вопрос не существует, но вы должны учитывать это в каждом конкретном случае. Часто это ясно, поскольку у вас разные классы, которые можно и нужно помещать в разные единицы перевода:
foo.hpp:
/* Only declaration of class foo we define below. Note that a declaration
* is not a definition. But a definition is always also a declaration */
class foo;
/* definition of a class foo. the same class definition can appear
in multiple translation units provided that each definition is the same
basicially, but only once per translation unit. This too is called the
"One Definition Rule" (ODR). */
class foo {
/* declaration of a member function doit */
void doit();
/* definition of an data-member age */
int age;
};
Объявите несколько бесплатных функций и объектов:
/* if you have translation unit non-local (with so-called extern linkage)
names, you declare them here, so other translation units can include
your file "foo.hpp" and use them. */
void getTheAnswer();
/* to avoid that the following is a definition of a object, you put "extern"
in front of it. */
extern int answerCheat;
foo.cpp:
/* include the header of it */
#include "foo.hpp"
/* definition of the member function doit */
void foo::doit() {
/* ... */
}
/* definition of a translation unit local name. preferred way in c++. */
namespace {
void help() {
/* ... */
}
}
void getTheAnswer() {
/* let's call our helper function */
help();
/* ... */
}
/* define answerCheat. non-const objects are translation unit nonlocal
by default */
int answerCheat = 42;
bar.hpp:
/* so, this is the same as above, just with other classes/files... */
class bar {
public:
bar(); /* constructor */
};
bar.cpp:
/* we need the foo.hpp file, which declares getTheAnswer() */
#include "foo.hpp"
#include "bar.hpp"
bar::bar() {
/* make use of getTheAnswer() */
getTheAnswer();
}
Обратите внимание, что имена в анонимном пространстве имен (как указано выше) не конфликтуют, поскольку они кажутся локальной единицей перевода. на самом деле это не так, у них просто уникальные имена, чтобы они не конфликтовали. если вам действительно нужны локальные имена единиц перевода (например, из-за совместимости с c, поэтому код C может вызывать вашу функцию), вы можете сделать это следующим образом:
static void help() {
/* .... */
}
В ODR также говорится, что у вас не может быть более одного определения любого объекта или не встроенной функции в одной программе (классы - это типы, а не объекты, поэтому это не относится к ним). Таким образом, вы должны следить за тем, чтобы не помещать в заголовки не встроенные функции или не помещать такие объекты, как "int foo;" в заголовках. Это вызовет ошибки компоновщика тогда, когда компоновщик попытается связать единицы перевода, включая эти заголовки, вместе.
Я надеюсь, что смогу вам немного помочь. Это был длинный ответ, действительно, где-то есть ошибки. Я знаю, что единица трансляции определяется строго иначе (вывод препроцессора). Но я думаю, что включение этого в вышеизложенное не принесет особой пользы, и это запутает вопрос. Пожалуйста, не стесняйтесь шлепать меня, если найдете настоящие ошибки :)
person
Johannes Schaub - litb
schedule
11.11.2008