C ++ Синглтон Конструктор и Деструктор - PullRequest
0 голосов
/ 04 мая 2010

Имеет ли значение, если реализация конструктора / деструктора предусмотрена в заголовочном файле или исходном файле? Например, какой способ предпочтительнее и почему?

Путь 1:

class Singleton
{
  public:
    ~Singleton() { }

  private:
    Singleton() { }
};

Способ 2:

class Singleton
{
  public:
    ~Singleton();

  private:
    Singleton();
};

В исходном файле .cc:

Singleton::Singleton()
{
}

Singleton::~Singleton()
{
}

Изначально у меня есть реализация в исходном файле, но меня попросили удалить ее. Кто-нибудь знает почему?

Ответы [ 5 ]

2 голосов
/ 04 мая 2010

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

1 голос
/ 04 мая 2010

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

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

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

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

0 голосов
/ 04 мая 2010

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

Однако есть еще одна тонкость, которую мы можем здесь исследовать. Скажем, конструктор в классе Singleton общедоступен:

class Singleton
{
public:
    Singleton(void);
    virtual ~Singleton(void);
};
//cpp file
Singleton::Singleton()
{
}


Singleton::~Singleton()
{
}

Если вы поместите приведенный выше код в статическую библиотеку, то у вас будет класс, который не может быть создан вне библиотеки . Не компилятор, который помешает вам сделать это, но компоновщик. Это ошибка, которую вы получите:

1> testrun.obj: ошибка LNK2001: неразрешенный внешний символ «public: virtual __thiscall Singleton :: ~ Singleton (void)» (?? 1Singleton @@ UAE @ XZ)
1> testrun.obj: ошибка LNK2001: неразрешенный внешний символ «public: __thiscall Singleton :: Singleton (void)» (?? 0Singleton @@ QAE @ XZ)
1> C: \ temp \ sotest \ Debug \ testrun.exe: фатальная ошибка LNK1120: 2 неразрешенных внешних кода

0 голосов
/ 04 мая 2010

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

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

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

0 голосов
/ 04 мая 2010

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

...