2014-10-08 4 views
1

나는에서/이제 std::string추상 형식의 필드를 선언 하시겠습니까? 포인터 또는 참조 선호?

struct Message 
{ 
    unsigned long id; 
    unsigned char command; 
    unsigned int value; 

    /* some more fields */ 
} 

내가 다른 클래스``그은을함으로써 그 클래스에 의존하고 있습니다에 structure Message를 분석 포맷에 대한

class Protocol 
{ 
public: 
    // format the string to json or xml depending on impl 
    virtual std::string& format(Message& msg) = 0; 
    // parse the message from json or xml depending on impl 
    virtual Message& parse(std::string& str) = 0; 
} 

같이 보입니다 추상 클래스가 그 유형의 회원. 내가 pProtocol 같은 포인터가 될 수 있기 때문에 내가 cProtocol 같은 클래스 형의 멤버를 선호한다 알고

  • : 물론이 멤버는 그래서 여기 Calculator

    // client.h 
    class Client 
    { 
    public: 
        Client(Protocol& protocol); 
    
        /* some methods, e.g. */ 
        void request(unsigned int amout); 
    
    private: 
        /* this is what the question below refers to */ 
        Protocol* pProtocol; // will compile 
        Protocol cProtocol; // won't compile (see below) 
        Protocol& rProtocol; // what does this mean? 
    } 
    
    // client.cpp 
    
    Client::Client(Protocol& protocol) : 
        // depending on the member 
        pProtocol(&protocol) // or 
        cProtocol(protocol) // or 
        rProtocol(protocol) 
    { 
    } 
    
    void Client::request(unsigned int amount) 
    { 
        Message msg; 
        msg.id = 1234; 
        msg.command = 100; 
        msg.value = amount; 
    
        std::string str = 
        // depending on the member 
             pProtocol->format(msg); // or 
             cProtocol.format(msg); // or 
             rProtocol.format(msg); 
    
        // some more code to send the string to the server 
    } 
    

    의 하위 유형이 될 것으로 예상된다 나의 질문 있습니다 NULL

  • 불행하게도이 메시지

    로 컴파일되지 않습니다

    추상 클래스 Protocol을 인스턴스화 할 수 없으므로 이해합니다.

  • 그래서 무엇을 선호합니까? 참조 멤버 또는 포인터 멤버?

  • 3 가지 옵션의 차이점은 무엇입니까? 특히 cProtocol 사이 rProtocol

  • 내가 생성자에서 rProtocol를 초기화하지 않는 경우 (.->과 사실을 제외하고 포인터가 NULL 될 수 있음)?이 컴파일됩니까? 무엇이 들어 있을까요? 이후 그것은 기본값으로 인스턴스화 될 수 없기 때문에!?

답변

2

나는 언어가 당신이 호출하여 자원을 관리 할 수 ​​있기 때문에 일반적으로, 당신은 포인터로 객체를 선호 pProtocol 같은 포인터가 NULL

수 있기 때문에 내가 cProtocol 같은 클래스 형의 멤버를 선호한다 알고 그들에 대한 소멸자. 그러나 std::shared_ptr<T> 또는 std::unique_ptr<T>과 같은 스마트 포인터를 사용하여 동일한 효과를 얻을 수 있습니다.

불행하게도이 메시지와 함께 컴파일되지 않습니다 추상 클래스 프로토콜을 인스턴스화 할 수 없기 때문에, 이해 "추상 형식 Protocol의 수 필드 Client::cProtocol를 선언 할 수 없습니다."

이것은 추상적 인 유형으로 개체를 잘라내는 것이 허용되지 않기 때문에 object slicing 때문에 완료됩니다.

그래서 무엇을 선호합니까? 참조 멤버 또는 포인터 멤버?참조를 사용하기 위해서는

, 세 가지 조건이 필요하다 :

  • 참조 된 객체가 생성자에서 사용할 수 있어야합니다
  • 참조 된 개체의 존재는 사용자가 설정할 수 없기 때문에 (필수이다 참조 번호 NULL) 및
  • 참조 된 개체를 다른 개체로 다시 지정하거나 나중에 참조를 "지우지"않아도됩니다.

이러한 세 가지 조건이 충족되면 참조를 사용할 수 있습니다. 이는 위의 세 가지 조건으로 인해 클래스 인스턴스가 참조 된 인스턴스에 대한 강력한 경계를 가지고 있다는 것을 독자가 코드에 알립니다.

3 가지 옵션의 차이점은 무엇입니까? 특히

( ->. 제외하고는 사실 포인터가 될 수 있음을 NULL) rProtocol cProtocoland 사이

cProtocoland (이것은 추상적 아니었다면, 그것은 것) 사본을 만들고 조각 떨어져 모든 파생 기능을. rProtocol은 다른 객체를 사용하고 다형성을 유지합니다. pProtocol은 할당하거나 재 할당 할 때 더 많은 유연성을 제공하며 NULL을 할당 할 때 더 많은 유연성을 제공합니다. 대신에 NULL- 포인터를 확인하고 선택적으로 복사 생성자, 할당 연산자 등과 관련된 리소스를 관리해야합니다.

생성자에 rProtocol을 초기화하지 않으면 어떻게됩니까? 이 컴파일됩니까? 무엇이 들어 있을까요? 이후 그것은 기본값으로 인스턴스화 될 수 없기 때문에!?

생성자에서 참조를 초기화 할 수 없으면 해당 멤버에 대한 참조를 전혀 사용할 수 없습니다. 포인터 만 선택할 수 있습니다.

+0

자세한 답변을 보내 주셔서 감사합니다. Java에서 왔고 객체 조각은 완전히 새로운 것이 었습니다! – ultimate