Подтвердить что ты не робот

С++, static vs. namespace против singleton

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

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

Теперь есть три способа:

  • создание класса со всем статичным (contra: потенциал "Невозможно вызвать функцию-член без объекта" - не все должно быть статическим)
  • создание одноэлементного класса (contra: я WILL нужен объект)
  • создание пространства имен (нет закрытого ключевого слова - зачем мне помещать его в пространство имен вообще?)

Каким будет способ для меня? Возможный способ объединения некоторых из этих способов?

Я подумал о чем-то вроде:

  • создавая синглтон, статические функции используют вспомогательную функцию одноэлементного объекта (возможно ли это? Я все еще в классе, но получаю доступ к объекту этого типа)
  • вызываемый при запуске программы, инициализирует все (- > убедитесь, что статика может получить доступ к функциям от объекта singleton)
  • доступ к публичным функциям только через MyClass:: PublicStaticFunction()

Спасибо.

4b9b3361

Ответ 1

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

Скрытие всего в классе - это то, что вы сделали бы на Java-подобном языке, но на С++ вам не нужно, и на самом деле использование пространств имен здесь является превосходной альтернативой, если только:

  • потому что люди не будут внезапно создавать экземпляры ваших объектов: с какой целью?
  • потому что для пространств имен не создается информация интроспекции (RTTI)

Вот типичная реализация:

// foo.h
#ifndef MYPROJECT_FOO_H_INCLUDED
#define MYPROJECT_FOO_H_INCLUDED

namespace myproject {
  void foo();
  void foomore();
}

#endif // MYPROJECT_FOO_H_INCLUDED

// foo.cpp
#include "myproject/foo.h"

namespace myproject {

namespace {
  typedef XXXX MyHelperType;

  void bar(MyHelperType& helper);
} // anonymous

void foo() {
  MyHelperType helper = /**/;
  bar(helper);
}

void foomore() {
  MyHelperType helper = /**/;
  bar(helper);
  bar(helper);
}
} // myproject

Анонимное пространство имен, аккуратно заправленное в исходный файл, представляет собой расширенный раздел private: не только клиент не может использовать то, что внутри, но он даже не видит его вообще (поскольку он находится в исходном файле) и, следовательно, (что имеет определенные преимущества ABI и время компиляции!)

Ответ 2

Не делайте его синглом

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

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

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

Ответ 3

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

Ответ 4

Как насчет использования ключевого слова static в глобальной области действия (что делает файл локальным для файла) в качестве замены конфиденциальности?

Ответ 5

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

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

Ответ 6

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

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

Если вы используете подход "C-like" и используете только функции верхнего уровня, вы можете сделать их частными, объявив их в .cpp файле, а не в общедоступном файле .h. Вы также должны сделать их статическими (или использовать анонимное пространство имен), если вы примете этот подход.