Вопрос

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

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

Предполагая, что я создал BitParser класс.Что бы это значило BitParser как выглядит определение класса?

Это было полезно?

Решение

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

Но, судя по вашему образцу, вам просто нужно создать общедоступный статический метод для вашего объекта 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;
}

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

Надеюсь, это поможет!Ваше здоровье.

Другие советы

Рассмотреть Решение Мэтта Прайса.

  1. В C ++ "статический класс" не имеет никакого значения.Ближайшая вещь - это класс, содержащий только статические методы и члены.
  2. Использование статических методов только ограничит вас.

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

Редактировать 2011-11-11

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

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

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

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

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

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

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

Почему это так?

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

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

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

Редактировать 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, кажется хорошим с точки зрения инкапсуляции...Это круто, потому что кто-то, смотрящий на HPP, не сможет (если не прибегнет к саботажу) получить доступ к Foo:: myGlobal.

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

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

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

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

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

Во-первых, коллектор ГЭС

// 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!

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

Действительно ли это имеет значение?

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

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

Редактировать 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 !!!

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

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

В BitParser.h

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

В BitParser.cpp

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

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

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

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

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

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

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

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

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

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

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

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

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

И как будто struct, class это также объявление типа.

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

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

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

В управляемом C ++ синтаксис статического класса следующий:-

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

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

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

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

MyNamespace.Function(blah);

Вот как сделать то же самое в C ++:

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
  }
}

Другой файл.h

#include "SharedModule.h"

OtherFile.cpp

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

В отличие от других управляемых языков программирования, "статический класс" в C ++ НЕ имеет НИКАКОГО значения.Вы можете использовать статическую функцию-член.

Как здесь было отмечено, лучшим способом достижения этого в C ++ может быть использование пространств имен.Но поскольку никто не упомянул о final ключевое слово здесь, я публикую то, что является прямым эквивалентом static class из C # это выглядело бы как в C ++ 11 или более поздней версии:

class BitParser final
{
public:
  BitParser() = delete;

  static bool GetBitAt(int buffer, int pos);
};

bool BitParser::GetBitAt(int buffer, int pos)
{
  // your code
}

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

class Class {
 public:
  void foo() { Static::bar(*this); }    

 private:
  int member{0};
  friend class Static;
};    

class Static {
 public:
  template <typename T>
  static void bar(T& t) {
    t.member = 1;
  }
};
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top