2010-03-01 6 views
5

첫째, 최신 코딩은 Java이고 "Java를 C++로 작성"하고 싶지 않습니다.자바 최종 회원 데이터에 해당하는 C++

여기 거래가 있습니다. 불변의 클래스를 만들어야합니다. 그것은 매우 간단합니다. 유일한 문제는 초기 값을 얻는 것이 약간의 작업이라는 것입니다. 그래서 단순히 초기화를 호출하여 내 멤버를 초기화 할 수 없습니다.

그런 클래스를 만드는 가장 좋은 방법은 무엇입니까? C++ 표준에서 변경 불가능한/최종 속성을 외부 세계에 어떻게 노출시킬 수 있습니까? 당신은 그것을 모방해야 아무도 없다

class Msg { 
    private: 
     int _rec_num; 
     int _seq; 
     string text; 
    public: 
     Msg(const char* buffer) { 
      // parse the buffer and get our member here... 
      // ... lots of code 
     } 

     // does this look like proper C++? 
     int get_rec_num() { return _rec_num; } 
    }; 

답변

7

C++은 클래스를 변경 불가능하게 만드는 훌륭한 메커니즘을 제공합니다. 당신이해야 할 것은 :

이 당신의 객체가 수정되지 않도록합니다 const

  • 선언 (그러나 정의되지 않음) operator= 민간 모두 공개 (그리고 아마도 보호) 메소드를 선언 그들이 창조 된 후에. 이제는 const 메서드를 사용하여 원하는 불변의 데이터 멤버에 액세스 할 수 있습니다.

    int get_rec_num() const { return _rec_num; } 
    
  • +0

    실제로 그것은 "const int get_rec_num() const ..."이어야합니다. - Hassan Syed –

    +3

    내장 유형의 경우 상수 값과 같은 것이 없기 때문에 차이가 없습니다. 리턴 타입이'int' 또는'const int'인지 상관없이'get_rec_num() = 7'을 쓸 수 없다. – fredoverflow

    0

    종료 자

    에 :

    여기에 샘플 클래스입니다. 정리 기능을 사용하거나 모든 리소스를 RAII 클래스에 캡슐화하십시오. 컴파일러는 응용 프로그램에 정적 기계를 배치하여 RAII 클래스에서 소멸자를 호출합니다. 즉, 소멸자를 통해 자원이 해제되는 범위를 벗어나면 소멸자가 호출됩니다. 불변성 및 초기화에

    뭔가 불변 일반적 경우

    const-correct 클래스 CONST 당신은 클래스가 초기화 될 때 그들에게있다 "쓰기"를 얻을 수있는 유일한 시간과 모든 구성원이있을 것이다. 그러나 귀하의 경우에는 가능하지 않을 수도 있습니다.

    일단 당신이 가지고 있으면 모든 리소스를 모으고 (기본 멤버가 아닌 기본 생성자를 통해) 클래스를 초기화하는 것이 좋습니다. 또 다른 대안 (나는 준수하지 않습니다)은 "주장"하는 것이 정확한지는 모르지만 일회성 게시물 구성 초기화에 대한 const 값에 쓰는 뮤 테이타 기능을 갖는 것입니다.

    +0

    내가 잘못되었거나 결국 호출되는 Finalizer가 절름발이 인 소멸자입니까? (필요에 따라 환경 설정이나 스마트 포인터로 객체를 사용하여 메모리 관리를 잘한다고 가정 할 때). –

    +0

    @ 마틴 나는 이것이 의미가 있다고 생각한다 - 통사론의 설탕; 내가 답을 타이핑 할 때 나는이 출현을 나 자신으로 가지고있었습니다. 그러나 RAII로 그립을 잡는 것보다 프로그래머에게 친숙합니다. 내가 더 젊은 프로그래머 였을 때 나는 C++로 finalizer를 갈구했다. –

    +0

    @Martin : Java에서 당신은 의미합니까? 그렇다면 파이널 라이저는 마침내 불리는 절름발이 소멸자가 아닙니다. 이것은 결국 호출 될 수도 안될 수도있는 의사 소멸자입니다. C++ 소멸자가 할 수없는 (실제로) 할 수있는 작업을 수행 할 수 있습니다. 가장 중요하고 짜증나는 것은 최종 객체 또는이 객체가 참조하는 다른 최종 객체를 부활시킬 수 있다는 것입니다. . –

    1

    당신은 올바른 길을 가고 있습니다. 모든 게터를 사용합니다. 세터가 없으면 클래스가 효과적으로 변경되지 않습니다.

    일부 구석의 경우를 잊지 마십시오. 연산자 =() 연산자를 비공개로 선언하고 구현하지 않아도되므로 누군가가 기본 컴파일러 생성 할당 연산자 등으로 객체를 무시할 수 없습니다. .

    1
    // does this look like proper C++? 
        int get_rec_num() { return _rec_num; } 
    

    당신은 (const를 개체의 멤버를 호출 할 수있는 const 참조)

    int get_rec_num() const { return _rec_num; } 
    

    를 사용해야합니다.

    +0

    실제로 "const int get_rec_num() const ..."이어야합니다. –

    +2

    값으로 반환하는 경우의 차이점은 무엇입니까? 그의 수업은 참고 문헌에 의한 반환이없는 한 불변이다. – pmr

    +0

    좋은 컨벤션, 그리고 우리가 그것을 강조 표시하면 지금 OP는 또 다른 개념을 배웁니다. –

    3

    나는 당신의 불변 멤버를 'const'로 표시하고 생성자 이니셜 라이저 목록에 값을 할당 할 것입니다.

    또한 클래스 외부에서 버퍼를 구문 분석하고 문자열을 생성자에 전달합니다. 이 같은

    뭔가 :

    class Msg { 
        private: 
        int _rec_num; 
        int _seq; 
        const std::string text; 
        public: 
        Msg(const std::string& str) : 
         text(str) 
        { 
    
        } 
    
        // does this look like proper C++? 
        int get_rec_num() const { return _rec_num; } 
    }; 
    
    // parse the buffer and get our parameter somewhere else 
    

    NB :

    당신은 'CONST'와 같은 클래스 내부의 상태를 변경하지 않는 멤버 함수를해야한다; const 개체를 사용하여 호출 할 수 있습니다.

    헤더 파일에 std :: string을 사용하면 안됩니다. 헤더를 포함하는 사람은 누구나이 '사용'을 강요합니다.

    +0

    개인적으로 중요한 작업을하는 생성자는 신경 쓰지 않습니다. 이 경우, 클래스가 불변이고 모든 멤버 함수가'const'가 될 것이라면, 멤버 변수'const '를 표시하는 것의 이점은 무시할 만하 며, 가능하지 않다는 단점을 훨씬 능가한다고 생각합니다 생성자로 하여금 유용하게 사용할 수있게합니다. 나는 그것이 클래스를 좋아하는 것이 얼마나 작은가에 달려 있다고 생각한다. 하나의 클래스가 두 가지 (값을 저장하고 버퍼에서 그 값을 얻는다)를 담당하는 것이 좋은 디자인인가? –

    0

    변수 불변 당신이 const 키워드 예 const int _rec_num을 사용해야하려면 : 귀하의 예를 들어 당신이 그것을 const를 만드는 것이 제공, 바로 보인다. Const 변수는 initialisation list을 통해서만 초기화 할 수 있으며, 생성자의 코드보다 먼저 호출됩니다. 이는 const 멤버 변수를 설정하는 생성자에서 어떠한 처리도 할 수 없다는 것을 의미합니다.

    두 가지 방법이 있습니다. 먼저 버퍼를 가져 와서 변수로 파싱하는 또 다른 내부 클래스를 만들 수 있습니다. 당신의 MSG 클래스로이의 const 버전을 넣고 초기화 목록에 넣고 :

    class MsgInner 
    { 
        public: 
        int _rec_num; 
    
        Msg(const char* buffer) { 
         // Your parsing code 
        } 
    }; 
    
    class Msg 
    { 
        public: 
        const MsgInner msg; 
    
        Msg(const char* buffer) : msg(buffer) 
        { // any other code } 
    }; 
    

    이 아마도 그래서 '표준'이 아니라 또 다른 관점입니다. 그렇지 않은 경우 get 메소드를 사용하여 다른 답변에서 제안한대로 수행 할 수도 있습니다.

    0

    우선, const로 선언 되었더라도 (필요하거나 권장하지 않는) 멤버를 효율적으로 그리고 생성시 초기화 할 수 있습니다.

    // Msg: pure data object; copy constructible but not modifiable. 
    class Msg 
    { 
    public: 
        Msg(int rec_num, ...) 
        : rec_num_(rec_num) 
        ... 
        {} 
    
        int rec_num() const 
        { return rec_num_; } 
        ... 
    private: 
        // prevent copying 
        Msg& operator=(Msg const&); 
    private: 
        int rec_num_; 
    }; 
    
    // MsgParser: responsible for parsing the buffer and 
    // manufacturing Msg's. 
    class MsgParser 
    { 
    public: 
        static Msg Parse(char const* buffer) 
        { 
        ... parse ... 
        return Msg(...); 
        } 
    }; 
    
    // Usage 
    Msg const msg = MsgParser::Parse(buffer); 
    

    이도 잘 잡고 별도의 클래스로 데이터를 구문 분석의 우려를 분리 :

    나는 아직도 당신이 두 개의 클래스 (의사 코드)로이 클래스를 분할하는 것이 좋습니다 것입니다.

    관련 문제