C ++에서 정적 클래스를 어떻게 작성합니까? 있어야한다. cout << “bit 5

C ++에서 정적 클래스를 어떻게 작성합니까? 나는 다음과 같은 것을 할 수 있어야한다.

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

BitParser클래스를 만들었다 고 가정합니다 . 무엇 것 BitParser같은 클래스 정의 모양을?



답변

예를 들어 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;
}

이 코드를 사용하여 예제 코드와 같은 방식으로 메소드를 호출 할 수 있습니다.

희망이 도움이됩니다! 건배.


답변

Matt Price의 솔루션을 고려하십시오 .

  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 정적 메소드”패턴의 클래스보다 강력합니다.

  • 정적 메소드는 클래스 개인 심볼에 액세스 할 수 있습니다
  • 개인 정적 메소드는 여전히 모든 사람이 볼 수 있으며 (액세스 할 수없는 경우) 캡슐화를 다소 위반합니다.
  • 정적 메소드는 앞으로 선언 할 수 없습니다
  • 라이브러리 헤더를 수정하지 않으면 클래스 사용자가 정적 메소드를 오버로드 할 수 없습니다.
  • 같은 네임 스페이스에서 (비정형 일 수있는) 비 멤버 함수보다 더 나은 정적 메소드로 수행 할 수있는 것은 없습니다.
  • 네임 스페이스는 고유 한 의미를 갖습니다 (결합 될 수 있고 익명 일 수 있음).
  • 기타

결론 : C ++에서 해당 Java / 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에서 액세스 권한이 부여 된 ALL (모든 기능과 동일) 기능 !!!

따라서 개인 정적 멤버를 사용하는 것은 피부에 문신을 한 연인 목록과 함께 누드로 밖에 나가는 것과 같습니다. 그리고 보너스 : 모든 사람들은 당신의 개인과 놀 수있는 권한을 가진 사람들의 이름을 가질 수 있습니다.

private 실제로 … 😀

“익명 네임 스페이스”솔루션

익명 네임 스페이스는 사적인 것을 비공개로 만들 수 있다는 이점이 있습니다.

먼저 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을 알고 있지 않습니다!

그녀의 피부에 문신을 한 그녀의 주소록으로 누드를 걷는 “정적 클래스”와는 달리, “익명”네임 스페이스는 완전히 옷을 입었습니다 .

정말 문제가 되나요?

코드의 사용자가 파괴 활동가가되지 않는 한, 무슨 것은 (나는 연습으로, 하나는 … 더러운 행동 정의되지 않은 해킹을 사용하여 공용 클래스의 민간 부분에 액세스 할 수있는 방법을 찾아 당신을 드리겠습니다) private이며 private, 심지어 경우 private헤더에 선언 된 클래스 섹션 에서 볼 수 있습니다 .

: 당신은 개인 회원에 액세스 할 수있는 또 다른 “개인 기능”을 추가해야하는 경우 그러나, 당신은 아직도 내가 걱정하고 지금까지와 같은 역설 헤더, 수정하여 전 세계에 선언해야 내가의 구현을 변경하는 경우를 내 코드 (CPP 부분), 인터페이스 (HPP 부분)가 바뀌지 않아야합니다. 인용 Leonidos : ” 이 캡슐화입니다!

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

일반적으로 이것은 코드 작성에 선호되는 방법입니다. 객체가 필요하지 않은 경우 클래스를 사용하지 마십시오.


답변

“정적”키워드를 클래스에 적용하는 방법을 찾고 있다면 C #에서와 같이

정적 클래스는 컴파일러를 손에 쥐고 인스턴스 메소드 / 변수를 작성하지 못하게합니다.

인스턴스 메소드 / 변수없이 일반 클래스를 작성하는 경우에도 마찬가지입니다. 이것은 C ++에서 수행하는 작업입니다.


답변

C ++에서는 정적 클래스가 아닌 클래스의 정적 함수를 작성하려고합니다.

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

그런 다음 내가 원하는 것으로 추정되는 객체를 인스턴스화하지 않고 BitParser :: getBitAt ()를 사용하여 함수를 호출 할 수 있어야합니다.


답변

같은 것을 쓸 수 있습니까 static class?

C ++ 11 N3337 표준 초안 부록 C 7.1.1 에 따르면 아니오 :

변경 : C ++에서 정적 또는 extern 지정자는 객체 또는 함수의 이름에만 적용 할 수 있습니다. C ++에서는 형식 지정과 함께 이러한 지정자를 사용하는 것은 불법입니다. C에서 이러한 지정자는 유형 선언에 사용될 때 무시됩니다. 예:

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

이론적 근거 : 스토리지 클래스 지정자는 유형과 연관 될 때 의미가 없습니다. C ++에서 클래스 멤버는 정적 스토리지 클래스 지정자로 선언 될 수 있습니다. 유형 선언에서 스토리지 클래스 지정자를 허용하면 코드가 혼동 될 수 있습니다.

그리고 같은 struct, class또한 형식 선언이다.

Annex A의 구문 트리를 걸어도 같은 내용을 추론 할 수 있습니다.

그것은 흥미 롭다 static structC 법적했지만, 영향을 미치지 아니합니다 : 왜 그리고 언제 C 프로그래밍 정적 구조를 사용하는 방법?


답변

여기에서 언급했듯이 C ++에서이를 달성하는 더 좋은 방법은 네임 스페이스를 사용하는 것일 수 있습니다. 그러나 아무도 final키워드 를 언급하지 않았으므로 static classC ++ 11 이상에서 C # 과 직접적으로 비슷한 모양을 게시하고 있습니다 .

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

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

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