개인, 공용 및 보호 상속의 차이점
차이점은 무엇이며 public
, private
그리고 protected
C에서 상속 ++? 내가 찾은 모든 질문은 특정 사례를 다룹니다.
이 질문에 답하기 위해 먼저 회원의 접근자를 제 말로 설명하고 싶습니다. 이미 알고있는 경우 "다음 :"제목으로 건너 뜁니다.
내가 알고있는 세 가지 접근자가 있습니다 : public
, protected
및 private
.
허락하다:
class Base {
public:
int publicMember;
protected:
int protectedMember;
private:
int privateMember;
};
- 알고있는 모든 것을
Base
또한 알고Base
들어 있습니다publicMember
. - 만 어린이들 (자녀)은 알고 있습니다
Base
포함되어 있습니다protectedMember
. - 아무도 모르지만
Base
알고privateMember
있습니다.
"알고있다"는 것은 "의 존재를 인정하고 따라서 액세스 할 수있다"는 의미입니다.
다음:
공용, 개인 및 보호 상속에서도 마찬가지입니다. 에서 상속 하는 클래스 Base
와 클래스 Child
를 생각해 봅시다 Base
.
- 상속 인 경우
public
, 알고 모든 것을Base
하고Child
또한 알고Child
상속에서Base
. - 상속이
protected
인 경우Child
, 및 그 자식 만 에서 상속 함을 인식합니다Base
. - 상속이
private
인 경우 다른 사람Child
은 상속을 인식 하지 않습니다 .
class A
{
public:
int x;
protected:
int y;
private:
int z;
};
class B : public A
{
// x is public
// y is protected
// z is not accessible from B
};
class C : protected A
{
// x is protected
// y is protected
// z is not accessible from C
};
class D : private A // 'private' is default for classes
{
// x is private
// y is private
// z is not accessible from D
};
중요 참고 : 클래스 B, C 및 D는 모두 변수 x, y 및 z를 포함합니다. 접근의 문제 일뿐입니다.
보호 및 개인 상속의 사용에 대해서는 여기에서 읽을 수 있습니다 .
상속의 가시성을 제한하면 코드가 일부 클래스가 다른 클래스를 상속한다는 것을 알 수 없게됩니다. 파생에서 기본으로의 암시 적 변환이 작동하지 않고 기본에서 파생으로의 변환도 작동 static_cast
하지 않습니다.
클래스의 멤버 / 친구 만 개인 상속을 볼 수 있으며 멤버 / 친구 및 파생 클래스 만 보호 된 상속을 볼 수 있습니다.
공공 상속
IS-A 상속. 버튼은 창이며 창이 필요한 곳이면 어디에서나 버튼을 전달할 수 있습니다.
class button : public window { };
보호 된 상속
구현 기간 동안 보호됩니다. 거의 유용하지 않습니다.
boost::compressed_pair
빈 클래스에서 파생하고 빈 기본 클래스 최적화를 사용하여 메모리를 절약하는 데 사용됩니다 (아래 예제에서는 해당 지점에 계속 유지하기 위해 템플릿을 사용하지 않음).struct empty_pair_impl : protected empty_class_1 { non_empty_class_2 second; }; struct pair : private empty_pair_impl { non_empty_class_2 &second() { return this->second; } empty_class_1 &first() { return *this; // notice we return *this! } };
개인 상속
조건에 따라 구현됩니다. 기본 클래스는 파생 클래스를 구현하기위한 용도로만 사용됩니다. 특성 및 크기가 중요한 경우 유용합니다 (함수 만 포함하는 빈 특성은 빈 기본 클래스 최적화를 사용합니다). 하지만 종종 봉쇄 가 더 나은 해결책입니다. 문자열의 크기는 매우 중요하므로 여기에서 자주 사용됩니다.
template<typename StorageModel> struct string : private StorageModel { public: void realloc() { // uses inherited function StorageModel::realloc(); } };
공개 회원
골재
class pair { public: First first; Second second; };
접근 자
class window { public: int getWidth() const; };
보호 된 회원
파생 클래스에 대한 향상된 액세스 제공
class stack { protected: vector<element> c; }; class window { protected: void registerClass(window_descriptor w); };
개인 회원
구현 세부 정보 유지
class window { private: int width; };
C 스타일 캐스트는 의도적으로 파생 클래스를 정의되고 안전한 방식으로 보호 또는 개인 기본 클래스로 캐스팅하고 다른 방향으로도 캐스팅 할 수 있도록 허용합니다. 구현 세부 사항에 따라 코드가 달라 지도록 만들 수 있기 때문에 모든 비용을 들이지 않아야하지만 필요한 경우이 기술을 사용할 수 있습니다.
기본 클래스의 공용 멤버가 파생 클래스에서 노출되는 방식과 관련이 있습니다.
- public-> 기본 클래스의 public 멤버는 public (일반적으로 기본값)입니다.
- protected-> 기본 클래스의 공용 멤버가 보호됩니다.
- private-> 기본 클래스의 public 멤버는 private이됩니다.
litb가 지적했듯이 공용 상속은 대부분의 프로그래밍 언어에서 볼 수있는 전통적인 상속입니다. 그것은 "IS-A"관계의 모델입니다. C ++ 특유의 AFAIK 인 사적 상속은 "IMPLEMENTED IN TERMS OF"관계입니다. 즉 , 파생 클래스에서 공용 인터페이스 를 사용 하고 싶지만 파생 클래스의 사용자가 해당 인터페이스에 액세스하는 것을 원하지 않습니다. 많은 사람들은이 경우 기본 클래스를 집계해야한다고 주장합니다. 즉, 기본 클래스를 전용 기본으로 사용하는 대신 기본 클래스의 기능을 재사용하기 위해 파생 된 멤버를 만들어야합니다.
이 세 키워드는 가시성 상속 모델 을 지정하기 위해 완전히 다른 컨텍스트에서도 사용됩니다 .
이 테이블은 하위 클래스가 완전히 정의되었을 때 구성 요소에 대한 결과 액세스를 제공하는 구성 요소 선언 및 상속 모델의 가능한 모든 조합을 수집합니다.
위의 표는 다음과 같은 방식으로 해석됩니다 (첫 번째 행을보십시오).
구성 요소가되는 경우 선언 으로 대중 과 그 클래스가되어 상속 으로 공공 결과 액세스 입니다 공공 .
예 :
class Super {
public: int p;
private: int q;
protected: int r;
};
class Sub : private Super {};
class Subsub : public Sub {};
변수에 대한 결과 액세스 p
, q
, r
수업 시간에 Subsub는 없다 아무도 .
다른 예시:
class Super {
private: int x;
protected: int y;
public: int z;
};
class Sub : protected Super {};
Sub 클래스의 변수 y
에 대한 결과 액세스 는 보호 되고 변수 에 대한 액세스 는 none 입니다.z
x
더 자세한 예 :
class Super {
private:
int storage;
public:
void put(int val) { storage = val; }
int get(void) { return storage; }
};
int main(void) {
Super object;
object.put(100);
object.put(object.get());
cout << object.get() << endl;
return 0;
}
이제 하위 클래스를 정의하겠습니다.
class Sub : Super { };
int main(void) {
Sub object;
object.put(100);
object.put(object.get());
cout << object.get() << endl;
return 0;
}
명명 된 클래스의 하위 클래스 Super
이거나 해당 Sub
클래스가 클래스에서 파생 된 Sub라는 정의 된 Super
클래스입니다. Sub
새로운 변수도 새로운 기능도 클래스 소개합니다. 클래스의 객체 가 실제로 클래스 객체 의 복사본이 된 Sub
후에 모든 특성을 상속 한다는 의미 입니까?Super
Super
아니 . 그렇지 않습니다.
다음 코드를 컴파일하면 put
및 get
메서드에 액세스 할 수 없다는 컴파일 오류 만 표시 됩니다. 왜?
가시성 지정자를 생략하면 컴파일러는 소위 개인 상속 을 적용 할 것이라고 가정합니다 . 이는 모든 공용 슈퍼 클래스 구성 요소가 개인 액세스 로 바뀌고 개인 슈퍼 클래스 구성 요소에 전혀 액세스 할 수 없음을 의미합니다. 결과적으로 하위 클래스 내에서 후자를 사용할 수 없음을 의미합니다.
이전에 사용했던 액세스 정책을 보존하고 싶다고 컴파일러에 알려야합니다.
class Sub : public Super { };
오해하지 마십시오 . Super 클래스의 개인 구성 요소 (저장 변수와 같은)가 다소 마술적인 방식으로 공용 구성 요소로 바뀐다는 의미는 아닙니다. 개인 구성 요소는 유지됩니다 개인 , 대중은 유지됩니다 공개 .
Sub
클래스의 객체는 클래스에서 생성 된 이전 형제 자매와 "거의"동일한 작업을 수행 할 수 있습니다 Super
. "거의" 하위 클래스라는 사실은 클래스가 수퍼 클래스의 개인 구성 요소에 대한 액세스 권한을 잃었 음을 의미하기 때문 입니다. Sub
스토리지 변수를 직접 조작 할 수 있는 클래스 의 멤버 함수를 작성할 수 없습니다 .
이것은 매우 심각한 제한입니다. 해결 방법이 있습니까?
네 .
세 번째 액세스 수준을 protected 라고 합니다. protected 키워드는 그것으로 표시된 컴포넌트 가 어떤 서브 클래스에 의해 사용될 때 공용 컴포넌트 처럼 동작하고 나머지 세계에서는 개인용 컴포넌트 처럼 보인다는 것을 의미합니다 . - 이것은 공개적으로 상속 된 클래스에만 해당됩니다 (예 : Super 클래스) .
class Super {
protected:
int storage;
public:
void put(int val) { storage = val; }
int get(void) { return storage; }
};
class Sub : public Super {
public:
void print(void) {cout << "storage = " << storage;}
};
int main(void) {
Sub object;
object.put(100);
object.put(object.get() + 1);
object.print();
return 0;
}
예제 코드에서 볼 수 있듯이 Sub
클래스에 대한 새로운 기능이 있으며 한 가지 중요한 작업 을 수행합니다. Super 클래스에서 스토리지 변수에 액세스합니다 .
변수가 private으로 선언 된 경우 불가능합니다. 주 함수 범위에서 변수는 어쨌든 숨겨져 있으므로 다음과 같이 작성하면됩니다.
object.storage = 0;
컴파일러는 그것이 error: 'int Super::storage' is protected
.
Finally, the last program will produce the following output:
storage = 101
Member in base class : Private Protected Public
Inheritance type : Object inherited as:
Private : Inaccessible Private Private
Protected : Inaccessible Protected Protected
Public : Inaccessible Protected Public
1) Public Inheritance:
a. Private members of Base class are not accessible in Derived class.
b. Protected members of Base class remain protected in Derived class.
c. Public members of Base class remain public in Derived class.
So, other classes can use public members of Base class through Derived class object.
2) Protected Inheritance:
a. Private members of Base class are not accessible in Derived class.
b. Protected members of Base class remain protected in Derived class.
c. Public members of Base class too become protected members of Derived class.
So, other classes can't use public members of Base class through Derived class object; but they are available to subclass of Derived.
3) Private Inheritance:
a. Private members of Base class are not accessible in Derived class.
b. Protected & public members of Base class become private members of Derived class.
So, no members of Base class can be accessed by other classes through Derived class object as they are private in Derived class. So, even subclass of Derived class can't access them.
Public inheritance models an IS-A relationship. With
class B {};
class D : public B {};
every D
is a B
.
Private inheritance models an IS-IMPLEMENTED-USING relationship (or whatever that's called). With
class B {};
class D : private B {};
a D
is not a B
, but every D
uses its B
in its implementation. Private inheritance can always be eliminated by using containment instead:
class B {};
class D {
private:
B b_;
};
This D
, too, can be implemented using B
, in this case using its b_
. Containment is a less tight coupling between types than inheritance, so in general it should be preferred. Sometimes using containment instead of private inheritance is not as convenient as private inheritance. Often that's a lame excuse for being lazy.
I don't think anyone knows what protected
inheritance models. At least I haven't seen any convincing explanation yet.
If you inherit publicly from another class, everybody knows you are inheriting and you can be used polymorphically by anyone through a base class pointer.
If you inherit protectedly only your children classes will be able to use you polymorphically.
If you inherit privately only yourself will be able to execute parent class methods.
Which basically symbolizes the knowledge the rest of the classes have about your relationship with your parent class
Protected data members can be accessed by any classes that inherit from your class. Private data members, however, cannot. Let's say we have the following:
class MyClass {
private:
int myPrivateMember; // lol
protected:
int myProtectedMember;
};
From within your extension to this class, referencing this.myPrivateMember
won't work. However, this.myProtectedMember
will. The value is still encapsulated, so if we have an instantiation of this class called myObj
, then myObj.myProtectedMember
won't work, so it is similar in function to a private data member.
Accessors | Base Class | Derived Class | World
—————————————+————————————+———————————————+———————
public | y | y | y
—————————————+————————————+———————————————+———————
protected | y | y | n
—————————————+————————————+———————————————+———————
private | | |
or | y | n | n
no accessor | | |
y: accessible
n: not accessible
Based on this example for java... I think a little table worth a thousand words :)
Summary:
- Private: no one can see it except for within the class
- Protected: Private + derived classes can see it
- Public: the world can see it
When inheriting, you can (in some languages) change the protection type of a data member in certain direction, e.g. from protected to public.
Private:
The private members of a base class can only be accessed by members of that base class .
Public:
The public members of a base class can be accessed by members of that base class, members of its derived class as well as the members which are outside the base class and derived class.
Protected:
The protected members of a base class can be accessed by members of base class as well as members of its derived class.
In short:
private: base
protected: base + derived
public: base + derived + any other member
I found an easy answer and so thought of posting it for my future reference too.
링크 http://www.learncpp.com/cpp-tutorial/115-inheritance-and-access-specifiers/에서
class Base
{
public:
int m_nPublic; // can be accessed by anybody
private:
int m_nPrivate; // can only be accessed by Base member functions (but not derived classes)
protected:
int m_nProtected; // can be accessed by Base member functions, or derived classes.
};
class Derived: public Base
{
public:
Derived()
{
// Derived's access to Base members is not influenced by the type of inheritance used,
// so the following is always true:
m_nPublic = 1; // allowed: can access public base members from derived class
m_nPrivate = 2; // not allowed: can not access private base members from derived class
m_nProtected = 3; // allowed: can access protected base members from derived class
}
};
int main()
{
Base cBase;
cBase.m_nPublic = 1; // allowed: can access public members from outside class
cBase.m_nPrivate = 2; // not allowed: can not access private members from outside class
cBase.m_nProtected = 3; // not allowed: can not access protected members from outside class
}
기본적으로 파생 클래스에있는 기본 클래스의 공용 및 보호 된 멤버에 대한 액세스 보호입니다. 공용 상속을 사용하면 파생 클래스가 기본의 공용 및 보호 된 멤버를 볼 수 있습니다. 개인 상속으로는 불가능합니다. protected를 사용하면 파생 클래스와이를 볼 수있는 파생 클래스가 있습니다.
'programing tip' 카테고리의 다른 글
JavaScript에서 선택적 함수 매개 변수를 수행하는 더 좋은 방법이 있습니까? (0) | 2020.09.29 |
---|---|
Git에서 특정 커밋을 병합하는 방법 (0) | 2020.09.28 |
데이터베이스와 함께 애플리케이션 제공 (0) | 2020.09.28 |
.NET의 형식 문자열에서 중괄호 (중괄호)를 이스케이프하는 방법 (0) | 2020.09.28 |
Firefox 또는 Chrome에서 수동으로 HTTP POST 요청을 실행하려면 어떻게합니까? (0) | 2020.09.28 |