기본 클래스에서 공개적으로 상속하지만 파생 클래스에서 기본 클래스의 일부 공용 메서드를 개인으로 만드는 방법은 무엇입니까?
예를 들어, 클래스 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 관점에서 무엇을하고 싶은지 이해해야합니다. 완전히 다른 두 가지 유형의 상속이 있습니다.
인터페이스의 상속.
implement
독립형 엔터티로 인터페이스 가 있는 Java 또는 기타 언어에서 수행 할 때 C ++의 빈 추상 클래스에서 공개적으로 상속 할 때도 발생합니다. 여기에서는 코드에 대해 전혀 신경 쓰지 않지만 컴파일러와 기본 / 파생 클래스를 사용하는 모든 사람에게이 파생 클래스가 기본 클래스의 특별한 종류이며 기본 클래스의 모든 속성을 가지고 있으며 정확히 다음 과 같이 동작 한다는 것을 알리고 싶습니다. 기본 클래스는 사용자가 볼 수있는 범위까지 수행하며 모든 알고리즘에서 기본 클래스 대신 사용할 수 있습니다.코드의 상속. 파생 클래스에서 재사용하려는 기본 클래스의 코드가 있습니다. 기본 클래스와 파생 클래스는 어떤 식 으로든 관련 될 필요가 없으며 코드를 재사용하기 만하면됩니다.
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
'development' 카테고리의 다른 글
XML 속성에 줄 바꿈을 저장하는 방법은 무엇입니까? (0) | 2020.12.29 |
---|---|
대기열을 사용하는 생산자 / 소비자 스레드 (0) | 2020.12.29 |
오른쪽으로 떠있는 것과 왼쪽으로 떠있는 것 사이에 div를 중앙에 배치 (0) | 2020.12.29 |
디렉터리 및 하위 디렉터리의 모든 파일을 시간 역순으로 나열하려면 어떻게합니까? (0) | 2020.12.28 |
Ajax 호출에서 세션 시간 초과 처리 (0) | 2020.12.28 |