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의 솔루션을 고려하십시오 .
- C ++에서 “정적 클래스”는 의미가 없습니다. 가장 가까운 것은 정적 메서드와 멤버 만있는 클래스입니다.
- 정적 메소드를 사용하면 제한됩니다.
당신이 원하는 것은 (그것이 대한 기능을 넣어, 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 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
}