2011-02-16 10 views
52

클래스의 일부 함수가 실제로 객체에 액세스하지 못하는 것으로 나타났습니다. 그래서 나는 그것들을 static으로 만들었습니다. 그렇다면 컴파일러는 액세스하는 모든 변수가 정적이어야한다는 것을 알려주었습니다. 나는 문자열 변수를 많이 가지고있다.C++에서 클래스의 정적 변수를 초기화 하시겠습니까?

string RE_ANY = "([^\\n]*)"; 
string RE_ANY_RELUCTANT = "([^\\n]*?)"; 

등등. 나는 결코 변경하지 않기 때문에 모두 static const로 만들었습니다. 그러나 내 프로그램은 클래스 밖으로 이동하면 컴파일됩니다. 그렇지 않으면 MSVC++ 2010 "정적 정적 정수 변수 만 클래스 내에서 초기화 될 수 있습니다."라는 불만이 있습니다.

글쎄 그건 불행한 일입니다. 해결 방법이 있습니까? 내가 속한 반 안으로 그들을 남겨두고 싶다.

답변

93

그들은 클래스 내부 초기화 할 수는 없지만, 그들은 소스 파일에서 클래스 외부에서 초기화 할 수 있습니다

// inside the class 
class Thing { 
    static string RE_ANY; 
    static string RE_ANY_RELUCTANT; 
}; 

// in the source file 
string Thing::RE_ANY = "([^\\n]*)"; 
string Thing::RE_ANY_RELUCTANT = "([^\\n]*?)"; 

업데이트

난 그냥 첫 번째 라인을 발견했습니다 귀하의 질문 - 하지 마십시오 그 기능을 만들고 싶어 static, 그들 const하고 싶어. 그것들을 static으로 만들면 객체와 더 이상 연관되지 않으므로 (비 정적 멤버에 액세스 할 수 없음) 데이터를 정적으로 만드는 것은이 유형의 모든 객체와 공유됨을 의미합니다. 이것은 당신이 원하는 것이 아닐 수도 있습니다. 그것들을 const으로 만드는 것은 단순히 회원을 수정할 수는 없지만 여전히 액세스 할 수 있음을 의미합니다.

+1

이들은 객체의 아무 것도 액세스하지 않고, 참조 인수. 그러므로 그들은 아마도'const'와'static' 둘 다 있어야합니다. –

+7

@Felix : 가능하지 않습니다.'const'는'this'를 수정하지 않는다는 것을 의미하며,'static' 메소드에는'this'가 없습니다. –

+0

@Matthieu : 아주 좋은 설명. 그래서'정적'이 맞습니다. –

15

정적 멤버 변수는 클래스에서 선언 된 다음 외부에서 정의해야합니다!

해결 방법은 없습니다. 실제 정의를 소스 파일에 넣기 만하면됩니다.


설명에서 정적 변수를 올바르게 사용하지 않는 것처럼 냄새가납니다. 절대 변경하지 않으면 상수 변수를 사용해야하지만 설명이 너무 일반적인 것입니다.

정적 멤버 변수는 클래스의 모든 인스턴스에 대해 항상 동일한 값을 유지합니다. 한 개체의 정적 변수를 변경하면 다른 모든 개체에 대해서도 변경됩니다 (실제로 인스턴스없이 액세스 할 수도 있음) 클래스의 - 예 : 개체 :).

+1

이제 정적 멤버 함수에서 사용할 수 있도록 정적이어야합니다. 그 규칙이 내부에서 선언되어야하고 클래스 외부에서 정의되어야하는 이유는 무엇입니까? 그건 나에게별로 의미가 없다. –

+1

@Felix Dombek : 이유는 클래스를 컴파일하고 링크하는 각 소스 파일에 대해 클래스가 선언되었지만 실제 변수는 한 번만 정의해야한다고 생각합니다. 이것이 다른 소스 파일에 정의 된 변수를 'extern'으로 명시 적으로 선언해야하는 동일한 이유입니다. – peoro

+1

@peoro : 합리적인 것처럼 보입니다! 그렇다면 왜 통합 데이터 유형이 허용됩니까? 그것도 허용되어서는 안된다. –

9

정적 변수가 상수 변수와 같지 않습니다.

클래스

struct Foo{ 
    const int a; 
    Foo(int b) : a(b){} 
} 

의 정수를 가변하여 우리는 매우

처럼 사용하는 정적 변수

struct Bar{ 
    static int a; 
    Foo(int b){ 
     a = b; 
    } 
} 
Bar::a = 0; // set value for a 

들어 같은

fooA = new Foo(5); 
fooB = new Foo(10); 
// fooA.a = 5; 
// fooB.a = 10; 

같이 선언 할

barA = new Bar(5); 
barB = new Bar(10); 
// barA.a = 10; 
// barB.a = 10; 
// Bar::a = 10; 

여기에 무슨 일이 일어나는 지보십시오.Foo가 인스턴스화 될 때 Foo의 각 인스턴스와 함께 인스턴스화되는 상수 변수는 Foo의 각 인스턴스에 대해 별도의 값을 가지며 Foo가 전혀 변경할 수 없습니다.

Bar의 경우 막대의 수에 상관없이 Bar :: a의 값은 하나뿐입니다. 그들은 모두이 가치를 공유하고, 당신은 Bar의 어떤 경우이든지 그것으로 접근 할 수 있습니다. 정적 변수는 public/private 규칙도 준수하므로 Bar 인스턴스 만 Bar :: a 값을 읽을 수 있습니다. 마이크 시모어는 당신에게 정답을 부여하고 있지만 추가

+0

허 .. 웃기는 찾아라. 아무도 "끔찍한"새로운 "쓸데없는"사용을 지적하지 않았다. 이 질문에 대해서는별로 관심이 없지만 그래야 할 필요가 없을 때 '신제품'을 사용하지 마십시오. – thecoshman

24

...
C는 ++ 컴파일러는 지시대로 선언 만 const 정적 정수형 클래스 본문에서 정의 할 수 있습니다.

class Foo 
{ 
    static const int someInt = 1; 
    static const short someShort = 2; 
    // etc. 
}; 

을 그리고 당신은 다른 유형으로,이 경우에 당신이 당신의 .cpp 파일에 정의해야 할 수없는 : 그래서 당신은 실제로 할 수 있습니다.

10

C++ 11 이후로는 constexpr 클래스 내에서 처리 할 수 ​​있습니다.

class stat { 
    public: 
     // init inside class 
     static constexpr double inlineStaticVar = 22; 
}; 

변수는 이제 액세스 할 수 있습니다 :

stat::inlineStaticVar 
+0

int, double, pointer 등에서는 매우 유용합니다. 문자열은 리터럴이나 참조가 아니기 때문에 질문의 문자열에는 사용할 수 없습니다. –

+0

좋은 지적. constexpr char RE_ANY [] = "([^ \\ n] *)"또는'constexpr std :: string_view RE_ANY ("([^ \ n n * *)", 9);' . – 0ax1

2

목표 대신 당신이 경우에 할 수는 * .cpp 파일,의 (헤더 파일에 정적 변수를 초기화하는 경우 "머리말 만"관용구에 집착하는 경우) 템플릿을 사용하여 초기화 문제를 해결할 수 있습니다. 템플리트 된 정적 변수는 다중 기호가 정의되지 않고 헤더에서 초기화 될 수 있습니다. ,

Static member initialization in a class template

1

선택적으로 .H 파일에 선언하지 않고 파일을 .CPP하는 모든 상수를 이동 :

는 예를 들어 여기를 참조하십시오. 익명의 네임 스페이스를 사용하여 cpp 모듈에서 보이지 않게합니다.

// MyClass.cpp 

#include "MyClass.h" 

// anonymous namespace 
namespace 
{ 
    string RE_ANY = "([^\\n]*)"; 
    string RE_ANY_RELUCTANT = "([^\\n]*?)"; 
} 

// member function (static or not) 
bool MyClass::foo() 
{ 
    // logic that uses constants 
    return RE_ANY_RELUCTANT.size() > 0; 
} 
5

다른 답변들 위에 덧붙이면됩니다. 고정 정적 멤버을 초기화하려면 다음과 같이하십시오.

정적 멤버를 평소와 같이 선언하십시오.

// myClass.h 
class myClass 
{ 
static complexClass s_complex; 
//... 
}; 

간단한 기능으로 수업을 초기화하십시오. 이것은 정적 멤버가 초기화 된 한 번 호출됩니다. complexClass의 복사 생성자가 사용될 것이므로 잘 정의되어 있어야합니다.

//class.cpp  
#include myClass.h 
complexClass initFunction() 
{ 
    complexClass c; 
    c.add(...); 
    c.compute(...); 
    c.sort(...); 
    // Etc. 
    return c; 
} 

complexClass myClass::s_complex = initFunction(); 
관련 문제