C ++에서 비공개 정적 데이터 멤버를 초기화하는 가장 좋은 방법은 무엇입니까? 헤더 파일에서 시도했지만 이상한 링커 오류가 발생합니다.
class foo
{
private:
static int i;
};
int foo::i = 0;
클래스 외부에서 개인 멤버를 초기화 할 수 없기 때문에 이것이 추측됩니다. 가장 좋은 방법은 무엇입니까?
답변
클래스 선언은 헤더 파일 (또는 공유되지 않은 경우 소스 파일)에 있어야합니다.
파일 : foo.h
class foo
{
private:
static int i;
};
그러나 초기화는 소스 파일에 있어야합니다.
파일 : foo.cpp
int foo::i = 0;
초기화가 헤더 파일에있는 경우 헤더 파일을 포함하는 각 파일에는 정적 멤버의 정의가 있습니다. 따라서 변수를 초기화하는 코드가 여러 소스 파일에 정의되므로 링크 단계에서 링커 오류가 발생합니다. 의 초기화는 static int i
기능 외부에서 수행해야합니다.
주 : 매트 커티스 : 아웃 포인트 C는 ++의 단순화를 허용하는, 상기 정적 부재 변수 CONST INT 형인 경우 (예를 들어 int
, bool
, char
). 그런 다음 헤더 파일의 클래스 선언 내에서 직접 멤버 변수를 선언하고 초기화 할 수 있습니다.
class foo
{
private:
static int const i = 42;
};
답변
A에 대한 변수 :
foo.h :
class foo
{
private:
static int i;
};
foo.cpp :
int foo::i = 0;
foo::i
프로그램에 인스턴스가 하나만있을 수 있기 때문 입니다. extern int i
헤더 파일과 int i
소스 파일 과 동일 합니다.
A의 상수 는 클래스 선언의 값을 바로 넣을 수 있습니다 :
class foo
{
private:
static int i;
const static int a = 42;
};
답변
C ++ 17부터 정적 멤버는 인라인 키워드로 헤더에 정의 될 수 있습니다 .
http://en.cppreference.com/w/cpp/language/static
“정적 데이터 멤버는 인라인으로 선언 될 수 있습니다. 인라인 정적 데이터 멤버는 클래스 정의에서 정의 될 수 있으며 기본 멤버 이니셜 라이저를 지정할 수 있습니다. 클래스 외부 정의가 필요하지 않습니다.”
struct X
{
inline static int n = 1;
};
답변
이 질문의 미래 시청자들을 위해, monkey0506이 제안하는 것을 피해야한다고 지적하고 싶습니다 .
헤더 파일은 선언 용입니다.
헤더 파일은 .cpp
직접 또는 간접적으로 모든 파일에 대해 한 번 컴파일되며 #includes
, 함수 외부의 코드는 프로그램 초기화시 이전에 실행됩니다 main()
.
를 foo::i = VALUE;
헤더에 넣으면 모든 파일에 대해 foo:i
값이 VALUE
무엇이든 .cpp
할당되며, 이러한 할당 main()
은 실행 되기 전에 결정되지 않은 순서 (링커에 의해 결정됨) 로 수행됩니다.
파일 #define VALUE
중 하나에서 다른 숫자가 되려면 어떻게해야 .cpp
합니까? 잘 컴파일되고 프로그램을 실행할 때까지 어느 쪽이 이길 지 알 수 없습니다.
같은 이유로 당신이 결코의 헤더에 실행 코드를 삽입하지 마십시오 파일.#include
.cpp
가드 포함 (항상 사용해야한다고 동의 함)은 다른 파일로부터 보호합니다 : #include
단일 .cpp
파일 을 컴파일하는 동안 동일한 헤더가 간접적으로 여러 번 d
답변
Microsoft 컴파일러 [1]를 사용하면 int
유사 하지 않은 정적 변수를 Microsoft specific을 사용하여 헤더 파일에서 정의 할 수 있지만 클래스 선언 외부에서 정의 할 수도 있습니다 __declspec(selectany)
.
class A
{
static B b;
}
__declspec(selectany) A::b;
나는 이것이 좋다고 말하는 것이 아니라, 그냥 할 수 있다고 말합니다.
[1] 요즘에는 MSC보다 더 많은 컴파일러 ( __declspec(selectany)
적어도 gcc와 clang)가 있습니다. 아마 더
답변
int foo::i = 0;
변수를 초기화하기위한 올바른 구문이지만 헤더가 아닌 소스 파일 (.cpp)로 이동해야합니다.
변수는 정적 변수이므로 컴파일러는 하나의 사본 만 작성하면됩니다. 컴파일러에서 어디에 삽입해야하는지 알려주려면 코드에 “int foo : i”줄이 있어야합니다. 그렇지 않으면 링크 오류가 발생합니다. 그것이 헤더에 있으면 헤더를 포함하는 모든 파일에 사본이 생길 것이므로 링커에서 여러 번 정의 된 기호 오류를 얻습니다.
답변
여기에 주석으로 추가 할 충분한 담당자가 없지만 IMO는 어쨌든 #include 가드로 헤더를 작성하는 것이 좋습니다 . 이미 별도의 CPP 파일을 사용하지 않는 한 정적 비 통합 멤버를 초기화하기 위해 파일을 사용할 필요는 없습니다.
#ifndef FOO_H
#define FOO_H
#include "bar.h"
class foo
{
private:
static bar i;
};
bar foo::i = VALUE;
#endif
이를 위해 별도의 CPP 파일을 사용할 필요가 없습니다. 물론 가능하지만 기술적 인 이유는 없습니다.