[c++] C ++에서 개인 정적 멤버를 초기화하는 방법은 무엇입니까?

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 파일을 사용할 필요가 없습니다. 물론 가능하지만 기술적 인 이유는 없습니다.