보호 된 방법에 대한 실제 시나리오


14

오늘 나는 기본적으로 protected부모의 비공개 메소드를 호출 할 필요가 거의 없기 때문에 기본적으로 C ++ 코드에서 메소드를 사용하지 않는다는 것을 알았습니다 . 템플릿 메소드 패턴에서 Java로 protected를 사용하지만 C ++에서 개인 메소드를 대체 할 수 있기 때문에 필요하지 않습니다 protected.

그렇다면 protectedC ++ 코드에서 메소드 를 사용하려는 실제 시나리오는 무엇 입니까?

(저는 일반적으로 구현 상속을 너무 좋아하지 않습니다.

답변:


12

여기에 예가 있습니다

class Base {
public:
  // other members ...

protected:
  ~Base() { }
};

다형성이 아닌 기본 클래스로 사용됩니다. 그러나 delete baseptr;소멸자가 액세스 할 수 없기 때문에 사용자가 전화를 걸 수 없습니다. 가상 소멸자가 없기 때문에 사람들이 그렇게 할 수 있도록하는 것은 정의되지 않은 행동입니다. Herb의 "Virtuality" 를 참조하십시오 .


1
너희들 무슨 일이야? 이것이 왜 하향 조정 되었습니까? 완벽하게 합리적입니다. 이해가되지 않으면 물어보십시오. 잘못되었다고 생각되면 설명해주세요. 우리는 당신의 통찰에서 배울 수 있습니다.
sbi

왜 -1입니까? 이것이 내가 처음 생각한 것입니다.
GManNickG

1
생성자와 소멸자는 내가 본 유일한 용도에 관한 것입니다. gcc는 여전히 소멸자가 이것에 비 가상적이라는 경고를 내 보냅니다.
Matthieu M.

+1 또한 보호 된 방법을 사용하여 몇 가지 책 조언을 적용합니다. 공개 가상 기능 대신 보호 된 가상 기능이있는 공용 인터페이스를 갖습니다.
Klaim

3

내가 자주 사용하는 한 가지 예는 내 객체 계층의 기본 클래스에서 보호 된 로거를 사용한다는 것입니다. 모든 기본 클래스는 로거에 액세스해야하지만 공개적으로 액세스 할 이유는 없습니다.

또한 템플릿 패턴을 사용하고 있고 기본 클래스에 사전 또는 사후 실행 메소드가있는 경우 대체 메소드에서 기본 구현을 호출 할 수 있습니다. 기본이 개인 전용이고 여전히 C ++로 덮어 쓸 수있는 경우 재정의 메서드에서 기본 구현을 호출 할 수 없습니다.


1
기본 클래스 메소드를 호출 하지 않아도 되는 템플릿 패턴이 아닙니까 ???
sbi

요점을 취했지만 기본 클래스 메소드를 호출하지 않아도되는 것이 전부라는 것은 아닙니다. 많은 상황에서 여러 수준을 가진 템플릿 패턴을 구현하는 객체 계층이 있으며, 각 계층에는 약간 더 많은 기능 / 확인이 추가됩니다. 이 경우 보호 방법이 필요합니다.
bryanatkinson

1

과거에 사용한 예일뿐입니다. 보호 된 메소드는 구현 별 함수를 제공하는 데 유용하지만 기본 클래스가 올바르게 추적 할 수 있습니다. 재정의 가능한 초기화 함수를 제공하지만 초기화 여부를 결정하는 상태가 있어야하는 기본 클래스를 고려하십시오.

class Base
{
private:
    bool m_bInitialized;
public:
    virtual void Initialize() = 0;

    void setInitialized() { m_bInitialized = true; };
    bool isInitialized() const { return m_bInitialized; };
}; // eo class Base

여기는 모두 좋고 훌륭합니다. 파생 클래스가 setInitialized()누구라도 호출 할 수 있다는 사실 을 부르지 않을 때를 제외하고는 (여기서는 이것을 보호 할 수 있으며 보호 된 메소드를 사용해야하는 또 다른 이유가 있습니다!). 가상 보호 멤버를 사용하는 클래스를 선호합니다.

class Base
{
private: 
    bool m_bInitialized;

protected:
    virtual void InitializeImpl() = 0;

public:

    void Initialize()
    {
        InitializeImpl();
        m_bInitialized = true;
    }; // eo Initialize

    bool isInitialized() const { return m_bInitialized; };
}; // eo class Base

새 클래스에서 모든 초기화는 여전히 파생 클래스에 위임됩니다. 예외가 발생하면 우리는 "이 클래스가 초기화되었습니다"라는 계약을 유지합니다.


0

다른 많은 기능과 마찬가지로 protected캡슐화를 어느 정도 확장 할 수 있습니다. 순수한 OO 개념을 깨는 것은 일반적으로 여러 가지 이유로 수행됩니다.

  1. 더 나은 성능 달성 (생각 inline)
  2. 코드를 이해하기 쉽게 만들고 아이러니하게도
  3. 더 나은 캡슐화 ( friend클래스 멤버에 대한 액세스를 몇 명의 친구로 제한 할 수 있음)

그리고 protected그 상자에있는 도구 중 하나에 불과하다. 파생 클래스에 일반 대중에게 숨겨져 야하는 클래스의 일부에 대한 액세스 권한을 부여하려는 경우 사용할 수 있습니다.

내가 사용한 한 가지 경우는 클래스의 모든 생성자를 protected만들고 기본적으로 해당 클래스를 추상적으로 만드는 것입니다 (파생 클래스의 객체의 하위 객체를 제외하고 인스턴스화 할 수는 없습니다).


0

아마도 디자인이 좋지 않았지만 다음과 같이했습니다.

// much simplified, of course
class input_device // base class
{
public:
    virtual ~input_device() {}

    // normally would be private with public caller, etc.
    virtual void update() = 0; 

    template <typename Func>
    void register_callback(Func func)
    {
        mButtonPressSignal.connect(func);
    }

protected:
    void trigger_signal(unsigned button)
    {
        mButtonPressSignal(button);
    }

private:
    boost::signals2::signal<void(unsigned)> mButtonPressSignal;
};

에서 파생 된 클래스는을 ( update()를) 호출하여 신호를 트리거 할 수 있습니다 trigger_signal(). 그러나 그것이 신호로 할 수있는 전부이기 때문에 신호 자체는 비공개로 남겨졌습니다. 파생 함수 만 트리거 할 수 있어야하므로 트리거 함수가 보호되었습니다.


0

"공용 메소드": 클래스가이를 수행 할 수 있습니다. "보호 된 메소드": 클래스가이를 수행하는 방법. "Private Methods": 클래스가 이것을 할 수있는 방법이지만 "나는 편집증이고 아무도 내가 어떻게하는지 알기를 원하지 않습니다."

// burguers.hpp

class BurguerClass {
  private: void addSecretRecipeSauce();  

  protected: virtual void addBread();  
  protected: virtual void addSalad();  
  protected: virtual void addMeat();
  protected: virtual void addExtraIngredients();

  public: virtual void makeBurguer();  
}

class CheeseBurguerClass: public BurguerClass {
  protected: override void addBread();  
  protected: override void addSalad();  
  protected: override void addMeat();
  protected: override void addExtraIngredients();

  protected: virtual void addCheese();

  public: override void makeBurguer();
}

class RanchStyleBurguerClass: public BurguerClass {
  protected: override void addBread();  
  protected: override void addSalad();  
  protected: override void addMeat();
  protected: override void addExtraIngredients();

  public: override void makeBurguer();
}

class EastCoastVegetarianStyleBurguerClass: public BurguerClass {
  protected: override void addBread();  
  protected: override void addSalad();  
  protected: override void addMeat();
  protected: override void addExtraIngredients();

  public: override void makeBurguer();
}

따라서 새로운 요리사 (개발자)가 패스트 푸드 식당에 도착합니다. 당신은 그것을 가르치고, burguers (공식적인 방법)를 판매하고, burguers를 준비하는 방법 (보호 된 방법), 그러나 "특허를받은"비밀 레시피 소스를 유지하십시오.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.