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


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.