development

기본 클래스에서 공개적으로 상속하지만 파생 클래스에서 기본 클래스의 일부 공용 메서드를 개인으로 만드는 방법은 무엇입니까?

big-blog 2020. 12. 29. 08:18
반응형

기본 클래스에서 공개적으로 상속하지만 파생 클래스에서 기본 클래스의 일부 공용 메서드를 개인으로 만드는 방법은 무엇입니까?


예를 들어, 클래스 Base에는 foo()bar(). 클래스 Derived클래스 에서 상속됩니다 Base. 수업 시간 Derived에는 foo()공개하지만 bar()비공개로 하고 싶습니다 . 다음 코드가이를 수행하는 정확하고 자연스러운 방법입니까?

class Base {
   public:
     void foo();
     void bar();
};

class Derived : public Base {
   private:
     void bar();
};

C ++ '03 표준의 섹션 11.3은이 기능을 설명합니다.

11.3 액세스 선언
파생 클래스 선언에서 해당 한정 ID를 언급하여 파생 클래스에서 기본 클래스 멤버의 액세스를 변경할 수 있습니다. 이러한 언급을 액세스 선언이라고합니다. Qualified-id 액세스 선언의 효과. 규정 된 ID를 사용하는 선언과 동일하게 정의됩니다.

그래서 두 가지 방법이 있습니다.

참고 : ISO C ++ '11부터는 Base::bar;주석에 명시된대로 액세스 선언 ( )이 금지됩니다. using Base::bar;대신 using-declaration ( )을 사용해야합니다.

1) public 상속을 사용한 다음 bar를 비공개로 만들 수 있습니다.

class Base {
public:
    void foo(){}
    void bar(){}
};

class Derived : public Base {
private:
    using Base::bar;
};

2) 개인 상속을 사용한 다음 foo를 공개 할 수 있습니다.

class Base {
public:
    void foo(){}
    void bar(){}
};

class Derived : private Base {
public:
    using Base::foo;
};

참고 : Derived 유형의 개체를 포함하는 Base 유형의 포인터 또는 참조가있는 경우 사용자는 여전히 멤버를 호출 할 수 있습니다.


에서 공개적으로 파생 Base하면 클래스 사용자는 항상 다음을 수행 할 수 있으므로 원하는 작업을 수행 할 수있는 방법이 없습니다 .

Derived d;
Base& b = d;
b.bar();

기본 클래스에서 파생 된 공개 클래스에서 공개 기본 클래스 함수에 액세스 할 수 없도록 만드는 것은 "올바르거나 자연스러운"것이 아닙니다. 대신 기본 클래스 인터페이스를 리팩토링하여 해당 함수가 공용이 아니거나 별도의 클래스로 분할되어야합니다.


첫째, OOP 관점에서 무엇을하고 싶은지 이해해야합니다. 완전히 다른 두 가지 유형의 상속이 있습니다.

  1. 인터페이스의 상속. implement독립형 엔터티로 인터페이스 있는 Java 또는 기타 언어에서 수행 할 때 C ++의 빈 추상 클래스에서 공개적으로 상속 할 때도 발생합니다. 여기에서는 코드에 대해 전혀 신경 쓰지 않지만 컴파일러와 기본 / 파생 클래스를 사용하는 모든 사람에게이 파생 클래스가 기본 클래스의 특별한 종류이며 기본 클래스의 모든 속성을 가지고 있으며 정확히 다음 과 같이 동작 한다는 것을 알리고 싶습니다. 기본 클래스는 사용자가 볼 수있는 범위까지 수행하며 모든 알고리즘에서 기본 클래스 대신 사용할 수 있습니다.

  2. 코드의 상속. 파생 클래스에서 재사용하려는 기본 클래스의 코드가 있습니다. 기본 클래스와 파생 클래스는 어떤 식 으로든 관련 될 필요가 없으며 코드를 재사용하기 만하면됩니다.

C ++의 공용 상속은 두 종류가 혼합되어 있으며 인터페이스 상속과 코드 상속도 얻습니다. 개인 상속은 다른 종류의 짐승이며, 코드 상속 얻습니다. 파생 클래스의 사용자는 기본 클래스 대신 사용할 수 없으며 사용자 관점에서 기본 및 파생 클래스는 전혀 관계가 없습니다.

struct Base {};
struct PublicDerived : public Base {};
struct PrivateDerived: private Base {};

Base * base; PublicDerived * public_derived; PrivateDerived * private_derived;

base = public_derived; //good
base = private_derived; //compilation error.

인터페이스를 변경하고 싶기 때문에 공용 상속 을 사용 해서는 안됩니다 . 인터페이스를 변경하면이 두 클래스가 서로 다른 동작을 가지며 서로 바꿔서 사용할 수 없다고 효과적으로 말할 수 있습니다. 그래서 당신이 정말로 원하는 것은 개인적으로 상속 한 다음 당신이 원하는 모든 메소드를 공개하는 것이고 그 반대는 아닙니다 .


Liskov Substitution Principle 에 따르면 공공 상속은 "is-a"를 모델로해야합니다. 당신이 Derived공개적으로 상속받는 것에 대해 말하는 Base것은 Base객체가 필요한 곳이라면 어디에서나 유형의 객체 Derived가 할 것이라는 것입니다.

에서 Derived사용할 수있는 일부 작업을 숨겨야하는 경우 Base모델링하는 것은 "is-a"이외의 것이며 공용 상속은 올바른 도구가 아닙니다.

다른 답변에서 자세히 설명했듯이 원하는 것은 개인 상속 또는 구성입니다.


이것을 가지고 있다고 가정 해 봅시다 :

class Foo{
public:
    void method1();
    void method2();
    void notGonnaSeeIt();
 private:
    //stuff
 };

효과적으로 래핑하려면 개인 상속을 수행하고 원하는 메서드를 Brian이 제안한 것처럼 공개 선언에 전달할 수 있습니다.

class Bar : private Foo{
    void methodA(){ method1(); }
    void methodB(){ method2(); }
    //more stuff
};

또는 데코레이터로 감쌀 수 있습니다

template<class T>
class Bar{
public:
    Bar(T *_input) : m_Input(_input){}
    void methodA() { m_Input->method1(); }
    void methodB() { m_Input->method2(); }
    //whatever else you need/want
private:
    T* m_Input;
};

Personally, I prefer the template way as it allows you to do the same thing with any class which inherits from Foo.


If you don't need to treat it as the base class later and only need some functions of the base class, you could use composition rather than inheritance? (C# is my first language, but you get the idea)

class Base {
    public void foo();
    public void bar();
};

class Derived {
    private Base _base;

    public void bar() {
        _base.bar();
    }
};

with C++ 11 you could do the following:

class Base {
   public:
     void foo();
     void bar();
};

class Derived : public Base {
   private:
     using Base::bar;  

};

This ensures that Base::bar() is not accessible from outside the Derived class. It's ofcourse still accessible from outside the Base class.

ReferenceURL : https://stackoverflow.com/questions/2986891/how-to-publicly-inherit-from-a-base-class-but-make-some-of-public-methods-from-t

반응형