your programing

보호 된 생성자의 실제 용도는 무엇입니까?

lovepro 2020. 10. 14. 08:14
반응형

보호 된 생성자의 실제 용도는 무엇입니까?


왜 아무도 생성자를 보호한다고 선언합니까? 생성자는 스택에서 생성을 허용하지 않기 위해 비공개로 선언된다는 것을 알고 있습니다.


클래스가 추상 클래스 인 경우 보호 된 생성자가 정확히 맞습니다. 이 상황에서는 객체가 클래스에서 인스턴스화되는 것을 원하지 않고 상속에만 사용합니다.

특정 구성 매개 변수 집합을 파생 클래스로 제한해야하는 경우와 같은 다른 사용 사례가 있습니다.


한 가지 용도는 공장 패턴 일 수 있습니다.


비공개 생성자는 생성자에 의해서만 보장 될 수없는 생성 요구 사항이있을 때 유용합니다. 예를 들어, 생성자 바로 뒤에 초기화 메서드를 호출해야하거나 객체가 컨테이너 / 관리자 객체에 자신을 등록해야하는 경우 생성자 외부에서 수행해야합니다. 생성자에 대한 액세스를 제한하고 팩토리 메서드 만 제공하면 사용자가받는 모든 인스턴스가 모든 보장을 이행하도록 할 수 있습니다. 이것은 또한 일반적으로 Singleton을 구현하는 데 사용되며, 이는 클래스가 만드는 또 다른 보증 일뿐입니다 (단일 인스턴스 만 있음).

생성자를 private이 아닌 보호로 만드는 이유는 private 대신에 다른 메서드 나 필드를 보호하도록 만드는 것과 동일하므로 자식이 상속 할 수 있습니다. 파생 클래스의 인스턴스에 대한 참조를 반환하는 기본 클래스에 가상이 아닌 공용 팩토리 메서드가 필요할 수 있습니다. 파생 클래스는 분명히 부모 생성자에 대한 액세스를 원하지만 여전히 팩토리 외부에서 생성하고 싶지는 않습니다.


보호 된 생성자는 메서드가 순수 가상이 아닌 경우 클래스를 효과적으로 추상화하는 데 사용할 수 있습니다.

친구 클래스가 재정의하지 않고 계속 사용할 수 있기 때문에 C ++의 의미에서 추상적이지는 않지만이를 선언해야합니다.


보호 된 생성자는 파생 된 멤버 만 해당 생성자를 사용하여 클래스 (및 파생 된 인스턴스)의 인스턴스를 생성 할 수 있음을 의미합니다. 이것은 약간 닭과 계란처럼 들리지만 때로는 클래스 팩토리를 구현할 때 유용합니다.


부작용이있는 팩토리 방법.

class mine {

  private:
    mine () {};

  protected:
    mine(int id) : m_id(id) {};

   int m_id;
   static int m_count;

  public:
    static mine* CreateOneOfMe() {
         return mine(m_count++);
    }

    int GetId() { return m_id; }

 };

이것은 클래스의 인스턴스를 생성하고 각각이 고유 한 증분 정수 ID를 갖도록 보장합니다. 사용하려는 생성자가 기본값이 아닌 경우 기본값도 숨겨야합니다.


하위 클래스가 인스턴스화자가 직접 액세스 할 수없는 생성자를 사용하도록합니다.


이를 생성 할 수있는 클래스를 제한하는 데 사용할 수 있습니다. 예를 들면 다음과 같습니다.

class Level
{
private:

 Level();
 ¨Level();

 friend class LevelManager;
};

인스턴스를 생성 할 수있는 유일한 클래스는 LevelManager 클래스이므로 Level 인스턴스가 LevelManager에 생성되었음을 항상 알 수 있습니다.


보호 된 생성자의 한 가지 용도는 CRTP 패턴을 구현하는 것입니다. 아래 코드를 참조하세요.

#include <iostream>
#include <assert.h>

template <class T>
class ComparableMixin {
public:
    bool operator !=(ComparableMixin &other) {
        return ~(*static_cast<T*>(this) == static_cast<T&>(other));
    }
    bool operator <(ComparableMixin &other) {
        return ((*(this) != other) && (*static_cast<T*>(this) <= static_cast<T&>(other)));
    }
    bool operator >(ComparableMixin &other) {
        return ~(*static_cast<T*>(this) <= static_cast<T&>(other));
    }
    bool operator >=(ComparableMixin &other) {
        return ((*static_cast<T*>(this) == static_cast<T&>(other)) || (*(this) > other));
    }
protected:
    ComparableMixin() {}
};

class Integer: public ComparableMixin<Integer> {
public:
 Integer(int i) {
     this->i = i;
 }
 int i;
 bool operator <=(Integer &other) {
     return (this->i <= other.i);
 }
 bool operator ==(Integer &other) {
     return (this->i == other.i);
 }
};
int main() {

    Integer i(0) ;
    Integer j(1) ;
    //ComparableMixin<Integer> c; //compilation error!
    assert (i < j );
    assert (i != j);
    assert (j >  i);
    assert (j >= i);

    return 0;
}

참고 URL : https://stackoverflow.com/questions/1057221/what-are-practical-uses-of-a-protected-constructor

반응형