C ++, статика против пространства имен против синглтона - PullRequest
30 голосов
/ 26 апреля 2011

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

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

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

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

Что бы я мог взять для меня? Возможный способ сочетания некоторых из этих способов?

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

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

Спасибо.

Ответы [ 6 ]

30 голосов
/ 26 апреля 2011

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

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

  • , потому что люди не будут внезапно создавать экземплярываших объектов: с какой целью?
  • , поскольку для пространств имен не генерируется информация о самоанализе (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 и времени компиляции!)

7 голосов
/ 26 апреля 2011

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

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

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

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

2 голосов
/ 26 апреля 2011

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

1 голос
/ 26 апреля 2011

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

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

1 голос
/ 26 апреля 2011

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

0 голосов
/ 26 апреля 2011

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

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

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

...