클래스 (이 경우 shape-factory)에 대한 개인 정적 상수를 갖고 싶습니다.
나는 일종의 무언가를 갖고 싶습니다.
class A {
private:
static const string RECTANGLE = "rectangle";
}
불행히도 C ++ (g ++) 컴파일러에서 다음과 같은 모든 종류의 오류가 발생합니다.
ISO C ++에서 멤버 ‘RECTANGLE’의 초기화를 금지합니다.
비 통합 유형 ‘std :: string’의 정적 데이터 멤버의 클래스 내부 초기화가 올바르지 않습니다.
오류 : ‘RECTANGLE’을 정적으로 만들기
이것은 이런 종류의 멤버 디자인이 표준을 준수하지 않는다는 것을 알려줍니다. #define 지시어를 사용하지 않고 어떻게 개인 리터럴 상수 (또는 아마도 공용)를 가지고 있습니까 (데이터 전역의 추악함을 피하고 싶습니다!)
도움을 주시면 감사하겠습니다.
답변
클래스 정의 외부에서 정적 멤버를 정의하고 거기에 이니셜 라이저를 제공해야합니다.
먼저
// In a header file (if it is in a header file in your case)
class A {
private:
static const string RECTANGLE;
};
그리고
// In one of the implementation files
const string A::RECTANGLE = "rectangle";
원래 사용하려는 구문 (클래스 정의의 초기화 프로그램)은 정수 및 열거 형 유형에만 허용됩니다.
C ++ 17부터는 원래 선언과 매우 유사한 또 다른 옵션 인 인라인 변수가 있습니다.
// In a header file (if it is in a header file in your case)
class A {
private:
inline static const string RECTANGLE = "rectangle";
};
추가 정의가 필요하지 않습니다.
또는 대신 이 변형으로 const
선언 할 수 있습니다 constexpr
. 을 의미 inline
하므로 더 이상 명시 적이 필요하지 않습니다 .constexpr
inline
답변
C ++ 11에서는 다음을 수행 할 수 있습니다.
class A {
private:
static constexpr const char* STRING = "some useful string constant";
};
답변
클래스 정의 내에서는 정적 멤버 만 선언 할 수 있습니다 . 클래스 외부에서 정의 해야합니다 . 컴파일 타임 적분 상수의 경우 표준은 멤버를 “초기화”할 수 있다는 예외를 만듭니다. 그래도 정의는 아닙니다. 예를 들어 주소를 정의하지 않으면 작동하지 않습니다.
상수에 const char [] 대신 std :: string을 사용하면 이점이 없다고 언급하고 싶습니다 . std :: string은 훌륭하지만 모두 동적 초기화가 필요합니다. 그래서, 당신이 같은 것을 쓰면
const std::string foo = "hello";
네임 스페이스 범위에서 foo의 생성자는 기본 시작 실행 직전에 실행되며이 생성자는 힙 메모리에 상수 “hello”의 복사본을 만듭니다. 실제로 RECTANGLE이 std :: string이어야하는 경우가 아니라면
// class definition with incomplete static member could be in a header file
class A {
static const char RECTANGLE[];
};
// this needs to be placed in a single translation unit only
const char A::RECTANGLE[] = "rectangle";
그곳에! 힙 할당 없음, 복사 없음, 동적 초기화 없음
건배
답변
이것은 추가 정보 일 뿐이지 만 실제로 헤더 파일에 문자열을 원하면 다음과 같이 시도하십시오.
class foo
{
public:
static const std::string& RECTANGLE(void)
{
static const std::string str = "rectangle";
return str;
}
};
나는 그것이 권장되는 것을 의심하지만.
답변
C ++ 17에서는 인라인 변수를 사용할 수 있습니다 .
class A {
private:
static inline const std::string my_string = "some useful string constant";
};
이것은 abyss.7의 답변 과 다릅니다 : 이것은 실제 std::string
객체를 정의합니다 .const char*
답변
클래스 내 초기화 구문을 사용하려면 상수는 상수 표현식으로 초기화 된 정수 또는 열거 유형의 정적 const 여야합니다.
이것이 제한 사항입니다. 따라서이 경우 클래스 외부에서 변수를 정의해야합니다. @AndreyT의 답변을 참조하십시오
답변
클래스 정적 변수는 헤더에서 선언 할 수 있지만 .cpp 파일에서 정의 해야 합니다. 정적 변수의 인스턴스는 하나만있을 수 있고 컴파일러는 생성 할 객체 파일을 결정할 수 없으므로 대신 결정을 내려야합니다.
C ++ 11의 선언으로 정적 값의 정의를 유지하기 위해 중첩 된 정적 구조를 사용할 수 있습니다. 이 경우 정적 멤버는 구조이며 .cpp 파일에 정의되어야하지만 값은 헤더에 있습니다.
class A
{
private:
static struct _Shapes {
const std::string RECTANGLE {"rectangle"};
const std::string CIRCLE {"circle"};
} shape;
};
개별 멤버를 초기화하는 대신 전체 정적 구조가 .cpp로 초기화됩니다.
A::_Shapes A::shape;
값은
A::shape.RECTANGLE;
또는-회원은 비공개이며 A에서만 사용할 수 있으므로
shape.RECTANGLE;
이 솔루션은 여전히 정적 변수의 초기화 순서 문제가 있습니다. 정적 값을 사용하여 다른 정적 변수를 초기화하면 첫 번째 변수는 아직 초기화되지 않을 수 있습니다.
// file.h
class File {
public:
static struct _Extensions {
const std::string h{ ".h" };
const std::string hpp{ ".hpp" };
const std::string c{ ".c" };
const std::string cpp{ ".cpp" };
} extension;
};
// file.cpp
File::_Extensions File::extension;
// module.cpp
static std::set<std::string> headers{ File::extension.h, File::extension.hpp };
이 경우 정적 변수 헤더 에는 링커에서 만든 초기화 순서에 따라 { “”} 또는 { “.h”, “.hpp”}가 포함됩니다.
@ abyss.7에서 언급했듯이 constexpr
변수 값을 컴파일 타임에 계산할 수있는 경우 에도 사용할 수 있습니다. 그러나 문자열을 선언 static constexpr const char*
하고 프로그램에서 std::string
달리 std::string
사용하면 상수를 사용할 때마다 새 객체가 생성 되므로 오버 헤드 가 발생합니다.
class A {
public:
static constexpr const char* STRING = "some value";
};
void foo(const std::string& bar);
int main() {
foo(A::STRING); // a new std::string is constructed and destroyed.
}