C ++에서 정적 클래스를 어떻게 작성합니까? 나는 다음과 같은 것을 할 수 있어야한다.
cout << "bit 5 is " << BitParser::getBitAt(buffer, 5) << endl;
BitParser
클래스를 만들었다 고 가정합니다 . 무엇 것 BitParser
같은 클래스 정의 모양을?
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;
}
이 코드를 사용하여 예제 코드와 같은 방식으로 메소드를 호출 할 수 있습니다.
희망이 도움이됩니다! 건배.
private: BitParser() {}
이렇게하면 누구나 인스턴스를 만들 수 없습니다.
BitParser() = delete;
생성자를 제거하려는 의도를 올바르게 전달하는 것이 좋습니다 (로 숨기는 것이 아니라 private
).
Matt Price의 솔루션을 고려하십시오 .
당신이 원하는 것은 (그것이 대한 기능을 넣어, C ++ 의미로 표현 인 것이다 네임 스페이스의 기능).
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 ++에서는 나쁜 스타일입니다.
때로는 정적 개인 멤버 변수를 사용해야하기 때문에 정적 메소드에 유리한 인수가있었습니다.
아래에 표시된 것처럼 다소 동의하지 않습니다.
// 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
실제로 ... :-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을 알고 있지 않습니다!
그녀의 피부에 문신을 한 그녀의 주소록으로 누드를 걷는 "정적 클래스"와는 달리, "익명"네임 스페이스는 완전히 옷을 입었습니다 .
코드의 사용자가 파괴 활동가가되지 않는 한, 무슨 것은 (나는 연습으로, 하나는 ... 더러운 행동 정의되지 않은 해킹을 사용하여 공용 클래스의 민간 부분에 액세스 할 수있는 방법을 찾아 당신을 드리겠습니다) private
이며 private
, 심지어 경우 private
헤더에 선언 된 클래스 섹션 에서 볼 수 있습니다 .
: 당신은 개인 회원에 액세스 할 수있는 또 다른 "개인 기능"을 추가해야하는 경우 그러나, 당신은 아직도 내가 걱정하고 지금까지와 같은 역설 헤더, 수정하여 전 세계에 선언해야 내가의 구현을 변경하는 경우를 내 코드 (CPP 부분), 인터페이스 (HPP 부분)가 바뀌지 않아야합니다. 인용 Leonidos : " 이 캡슐화입니다! "
멤버가 아닌 함수가있는 네임 스페이스보다 클래스 정적 메서드가 실제로 더 나은 경우는 언제입니까?
기능을 함께 그룹화하고 해당 그룹을 템플리트에 공급해야하는 경우 :
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 !!!
클래스가 템플릿 매개 변수 일 수 있으면 네임 스페이스가 될 수 없기 때문입니다.
#define private public
헤더에 다음 코드를 추가하는 것입니다 ... ^ _ ^ ...
utilities
네임 스페이스를. 이런 식으로,이 함수는 단위 테스트를 할 수 있으며, 여전히 개인 멤버에 대한 특별한 액세스 권한이 없습니다 (함수 호출시 매개 변수로
namespace
의지에 뛰어 global
들어도 숨겨져 있지만 회원에게 접근 할 수 없습니까? 분명히 그들은 추측해야하지만, 의도적으로 코드를 난독 화하지 않는 한 변수 이름은 추측하기 쉽습니다.
네임 스페이스에서 무료 함수를 만들 수도 있습니다.
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 ++에서 수행하는 작업입니다.
static
200 번 쓰거나 잘라내거나 붙여 넣지 못하게하는 컴파일러 손을 잡는 것이 좋습니다.
같은 것을 쓸 수 있습니까 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 struct
C 법적했지만, 영향을 미치지 아니합니다 : 왜 그리고 언제 C 프로그래밍 정적 구조를 사용하는 방법?
여기에서 언급했듯이 C ++에서이를 달성하는 더 좋은 방법은 네임 스페이스를 사용하는 것일 수 있습니다. 그러나 아무도 final
키워드 를 언급하지 않았으므로 static class
C ++ 11 이상에서 C # 과 직접적으로 비슷한 모양을 게시하고 있습니다 .
class BitParser final
{
public:
BitParser() = delete;
static bool GetBitAt(int buffer, int pos);
};
bool BitParser::GetBitAt(int buffer, int pos)
{
// your code
}
이것은 C ++에서 C ++에서 수행하는 방식과 유사합니다.
C # file.cs에서는 공용 함수 내에 private 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
}
}
OtherFile.h
#include "SharedModule.h"
OtherFile.cpp
//Call the functions using the hidden variables
SharedData::SetError("Hello", "World");
SharedData::DisplayError();
네임 스페이스가 "정적 클래스"를 달성하는 데 그다지 유용하지 않은 경우는 상속보다 구성을 달성하기 위해 이러한 클래스를 사용할 때입니다. 네임 스페이스는 클래스의 친구가 될 수 없으므로 클래스의 비공개 멤버에 액세스 할 수 없습니다.
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;
}
};
(많은) 대안 중 하나이지만, (제 생각에 가장 우아한) 네임 스페이스와 개인 생성자를 사용하여 정적 동작을 에뮬레이션하는 것과 비교할 때 C ++에서 "인스턴스화 할 수없는 클래스"동작을 달성하는 방법은 다음과 같습니다. private
액세스 수정자를 사용하여 더미 순수 가상 함수를 선언하십시오 .
class Foo {
public:
static int someMethod(int someArg);
private:
virtual void __dummy() = 0;
};
C ++ 11을 사용하는 final
경우 클래스 선언에서 지정자를 사용하여 클래스가 상속되지 않도록 (정적 클래스의 동작을 모방하기 위해) 추가 클래스를 사용 하여 다른 클래스가 상속하지 못하도록 제한 할 수 있습니다 .
// C++11 ONLY
class Foo final {
public:
static int someMethod(int someArg);
private:
virtual void __dummy() = 0;
};
어리 석고 비논리적 인 것처럼 C ++ 11에서는 "재정의 할 수없는 순수한 가상 함수"를 선언 할 수 있습니다.이를 통해 클래스 선언과 함께 final
정적 동작을 순수하고 완벽하게 구현할 수 있습니다. 상속 할 수없는 클래스와 더미 함수는 어떤 식 으로든 재정의되지 않습니다.
// C++11 ONLY
class Foo final {
public:
static int someMethod(int someArg);
private:
// Other private declarations
virtual void __dummy() = 0 final;
}; // Foo now exhibits all the properties of a static class