Как создать статический класс в С++?

Как создать статический класс в С++? Я должен был бы сделать что-то вроде:

cout << "bit 5 is " << BitParser::getBitAt(buffer, 5) << endl;

Предполагая, что я создал класс BitParser. Каким будет определение класса BitParser?

Ответ 1

Если вы ищете способ применения "статического" ключевого слова к классу, например, вы можете в С#, например, вы не сможете использовать Managed С++.

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

BitParser.h

class BitParser
{
 public:
  static bool getBitAt(int buffer, int bitIndex);

  // ...lots of great stuff

 private:
  // Disallow creating an instance of this object
  BitParser() {}
};

BitParser.cpp

bool BitParser::getBitAt(int buffer, int bitIndex)
{
  bool isBitSet = false;
  // .. determine if bit is set
  return isBitSet;
}

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

Надеюсь, что это поможет! Приветствия.

Ответ 2

Рассмотрим решение по цене Matt.

  • В С++ "статический класс" не имеет никакого значения. Ближайшей вещью является класс с только статическими методами и членами.
  • Использование статических методов ограничит вас только.

Что вы хотите, выраженное в семантике С++, поставить вашу функцию (для нее есть функция) в пространстве имен.

Изменить 2011-11-11

В С++ нет "статического класса" . Ближайшей концепцией будет класс с только статическими методами. Например:

// header
class MyClass
{
   public :
      static void myMethod() ;
} ;

// source
void MyClass::myMethod()
{
   // etc.
}

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

В С++ то, что вы действительно хотите, это функция, не являющаяся членом, которую вы объявите в пространстве имен:

// header
namespace MyNamespace
{
   static void myMethod() ;
}

// source
namespace MyNamespace
{
   void myMethod()
   {
      // etc.
   }
}

Почему это?

В С++ пространство имен более мощно, чем классы для шаблона Java static method, потому что:

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

Заключение: не копируйте и не вставляйте этот шаблон Java/С# в С++. В Java/С# шаблон является обязательным. Но в С++ это плохой стиль.

Изменить 2010-06-10

Был аргумент в пользу статического метода, потому что иногда нужно использовать статическую частную переменную-член.

Я не согласен, как показано ниже:

Решение "Статический частный член"

// HPP

class Foo
{
   public :
      void barA() ;
   private :
      void barB() ;
      static std::string myGlobal ;
} ;

Во-первых, myGlobal называется myGlobal, потому что он по-прежнему является глобальной частной переменной. Посмотрите на источник CPP, чтобы уточнить, что:

// CPP
std::string Foo::myGlobal ; // You MUST declare it in a CPP

void Foo::barA()
{
   // I can access Foo::myGlobal
}

void Foo::barB()
{
   // I can access Foo::myGlobal, too
}

void barC()
{
   // I CAN'T access Foo::myGlobal !!!
}

На первый взгляд факт, что свободная функция barC не может получить доступ к Foo:: myGlobal, кажется хорошей с точки зрения инкапсуляции... Это круто, потому что кто-то, смотрящий на ГЭС, не сможет (если не прибегнуть к саботажу ) для доступа к Foo:: myGlobal.

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

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

private действительно... :-D

Решение "Анонимные пространства имен"

У анонимных пространств имен будет преимущество, заключающееся в том, что частные вещи становятся частными.

Сначала заголовок HPP

// HPP

namespace Foo
{
   void barA() ;
}

Просто, чтобы быть уверенным, что вы заметили: нет никакого бесполезного объявления barB и myGlobal. Это означает, что никто, кто читает заголовок, не знает, что скрывается за barA.

Тогда CPP:

// CPP
namespace Foo
{
   namespace
   {
      std::string myGlobal ;

      void Foo::barB()
      {
         // I can access Foo::myGlobal
      }
   }

   void barA()
   {
      // I can access myGlobal, too
   }
}

void barC()
{
   // I STILL CAN'T access myGlobal !!!
}

Как вы можете видеть, например, так называемое объявление "статического класса" , fooA и fooB все еще могут получить доступ к myGlobal. Но никто другой не может. И никто другой вне этого CPP не знает, что fooB и myGlobal даже существуют!

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

Это действительно имеет значение?

Если пользователи вашего кода не являются саботажниками (я позволю вам в качестве упражнения найти способ доступа к частной части открытого класса с использованием грязного поведения - undefined hack...), что private - private, даже если он отображается в разделе private класса, объявленного в заголовке.

Тем не менее, если вам нужно добавить еще одну "частную функцию" с доступом к частному члену, вы все равно должны объявить ее во всем мире, изменив заголовок, что является парадоксально, насколько мне известно: Если я изменил реализацию моего кода (часть CPP), тогда интерфейс (часть HPP) НЕ должен меняться. Цитата Leonidas: " Это ENCAPSULATION!"

Изменить 2014-09-20

Когда классы статические методы на самом деле лучше, чем пространства имен с не-членными функциями?

Когда вам нужно объединить функции и передать эту группу в шаблон:

namespace alpha
{
   void foo() ;
   void bar() ;
}

struct Beta
{
   static void foo() ;
   static void bar() ;
};

template <typename T>
struct Gamma
{
   void foobar()
   {
      T::foo() ;
      T::bar() ;
   }
};

Gamma<alpha> ga ; // compilation error
Gamma<Beta> gb ;  // ok
gb.foobar() ;     // ok !!!

Поскольку, если класс может быть параметром шаблона, пространства имен не могут.

Ответ 3

Вы также можете создать свободную функцию в пространстве имен:

В BitParser.h

namespace BitParser
{
    bool getBitAt(int buffer, int bitIndex);
}

В BitParser.cpp

namespace BitParser
{
    bool getBitAt(int buffer, int bitIndex)
    {
        //get the bit :)
    }
}

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

Ответ 4

Если вы ищете способ применения "статического" ключевого слова к классу, например, вы можете в С#, например

статические классы - это просто компилятор, который держит вас и не позволяет вам писать какие-либо методы/переменные экземпляра.

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

Ответ 5

Могу ли я написать что-то вроде static class?

Нет, в соответствии с С++ 11 N3337 стандартный проект Приложение C 7.1.1:

Изменить: в С++ статические или внешние спецификации могут применяться только к именам объектов или функций. Использование этих спецификаторов с объявлениями типов является незаконным в С++. В C эти спецификаторы игнорируются при использовании на объявления типов. Пример:

static struct S {    // valid C, invalid in C++
  int i;
};

Обоснование: Спецификаторы класса хранения не имеют никакого значения при привязке к типу. В С++ класс члены могут быть объявлены с помощью спецификатора класса статического хранилища. Разрешение спецификаторов класса хранения по типу объявления могут сделать код запутанным для пользователей.

И как struct, class также является объявлением типа.

То же самое можно сделать, пройдя дерево синтаксиса в приложении А.

Интересно отметить, что static struct был законным в C, но не имел никакого эффекта: Почему и когда использовать статические структуры в программировании на C?

Ответ 6

В С++ вы хотите создать статическую функцию класса (а не статический класс).

class BitParser {
public:
  ...
  static ... getBitAt(...) {
  }
};

Затем вы можете вызвать функцию с помощью BitParser:: getBitAt() без создания экземпляра объекта, который, как я полагаю, является желаемым результатом.

Ответ 7

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

Ответ 8

В управляемом С++ статический класс синтаксиса: -

public ref class BitParser abstract sealed
{
    public:
        static bool GetBitAt(...)
        {
            ...
        }
}

... лучше поздно, чем никогда...

Ответ 9

Это похоже на способ С# сделать это в С++

В С# file.cs вы можете иметь private var внутри публичной функции. Когда в другом файле вы можете использовать его, вызвав пространство имен с помощью функции, как в:

MyNamespace.Function(blah);

Здесь, как перевести то же самое в С++:

SharedModule.h

class TheDataToBeHidden
{
  public:
    static int _var1;
    static int _var2;
};

namespace SharedData
{
  void SetError(const char *Message, const char *Title);
  void DisplayError(void);
}

SharedModule.cpp

//Init the data (Link error if not done)
int TheDataToBeHidden::_var1 = 0;
int TheDataToBeHidden::_var2 = 0;


//Implement the namespace
namespace SharedData
{
  void SetError(const char *Message, const char *Title)
  {
    //blah using TheDataToBeHidden::_var1, etc
  }

  void DisplayError(void)
  {
    //blah
  }
}

OtherFile.h

#include "SharedModule.h"

OtherFile.cpp

//Call the functions using the hidden variables
SharedData::SetError("Hello", "World");
SharedData::DisplayError();

Ответ 10

В отличие от другого управляемого языка программирования, "статический класс" не имеет смысла в С++. Вы можете использовать статическую функцию-член.