다중 상속을 사용할 때 어떻게 죽음의 다이아몬드를 피할 수 있습니까?
http://en.wikipedia.org/wiki/Diamond_problem
그게 무슨 뜻인지 알지만 피하려면 어떤 조치를 취할 수 있습니까?
실제 예 :
class A {};
class B : public A {};
class C : public A {};
class D : public B, public C {};
클래스 D가 B와 C에서 어떻게 상속되는지 주목하십시오. 그러나 B와 C는 모두 A에서 상속합니다. 그러면 vtable에 포함 된 클래스 A의 2 개의 복사본이 생성됩니다.
이를 해결하려면 가상 상속이 필요합니다. 가상으로 상속되어야하는 클래스 A입니다. 따라서 다음과 같이 문제가 해결됩니다.
class A {};
class B : virtual public A {};
class C : virtual public A {};
class D : public B, public C {};
가상 상속. 그것이 거기에있는 이유입니다.
나는 인터페이스의 다중 상속만을 사용하고 싶다. 클래스의 다중 상속이 때때로 매력적이지만 정기적으로 의존하는 경우 혼란스럽고 고통 스러울 수도 있습니다.
상속은 강력하고 강력한 무기입니다. 정말로 필요할 때만 사용하십시오. 과거에 다이아몬드 상속은 사용자가 "직원"이지만 그들도 "위젯 리스너"이자 ...
이러한 경우 여러 상속 문제가 발생하기 쉽습니다.
소유자에게 다시 구성 및 포인터를 사용하여 문제를 해결했습니다.
전에:
class Employee : public WidgetListener, public LectureAttendee
{
public:
Employee(int x, int y)
WidgetListener(x), LectureAttendee(y)
{}
};
후:
class Employee
{
public:
Employee(int x, int y)
: listener(this, x), attendee(this, y)
{}
WidgetListener listener;
LectureAttendee attendee;
};
예, 액세스 권한은 다르지만 코드를 복제하지 않고 그러한 접근 방식을 피할 수 있다면 덜 강력하기 때문에 더 좋습니다. (대안이 없을 때를 대비하여 전력을 절약 할 수 있습니다.)
class A {};
class B : public A {};
class C : public A {};
class D : public B, public C {};
여기에서 클래스 A의 속성은 클래스 D에서 두 번 반복되어 더 많은 메모리를 사용합니다. 따라서 메모리를 절약하기 위해 Vtable에 저장된 클래스 A의 상속 된 모든 속성에 대한 가상 속성을 만듭니다.
글쎄, Dreaded Diamond의 가장 좋은 점은 그것이 발생할 때 오류라는 것입니다. 피하는 가장 좋은 방법은 미리 상속 구조를 파악하는 것입니다. 예를 들어 내가 작업하는 한 프로젝트에는 뷰어와 편집자가 있습니다. Editor는 Viewer의 논리적 하위 클래스이지만 모든 Viewer는 TextViewer, ImageViewer 등의 하위 클래스이므로 Editor는 Viewer에서 파생되지 않으므로 최종 TextEditor, ImageEditor 클래스가 다이아몬드를 피할 수 있습니다.
다이아몬드를 피할 수없는 경우 가상 상속을 사용합니다. 그러나 가상베이스의 가장 큰주의 사항 은 가장 많이 파생 된 클래스 에서 가상베이스의 생성자를 호출 해야 한다는 것입니다. 즉, 파생되는 클래스는 생성자 매개 변수를 제어 할 수 없습니다. 또한, 가상 기지의 존재는 체인을 통해 캐스팅 할 때 성능 / 공간 패널티를 초래하는 경향이 있지만, 첫 번째 이후에는 더 많은 패널티가 있다고 생각하지 않습니다.
또한 어떤 염기를 사용하고 싶은지 명확하다면 언제든지 다이아몬드를 사용할 수 있습니다. 때로는 유일한 방법입니다.
더 나은 클래스 디자인을 제안합니다. 다중 상속을 통해 가장 잘 해결되는 문제가 있다고 확신하지만 먼저 다른 방법이 있는지 확인하십시오.
그렇지 않은 경우 가상 기능 / 인터페이스를 사용하십시오.
위임으로 상속을 사용합니다. 그러면 두 클래스 모두 기본 A를 가리 키지 만 A로 리디렉션하는 메서드를 구현해야합니다. A의 보호 된 멤버를 B, C 및 D의 "개인"멤버로 바꾸는 부작용이 있지만 지금은 그렇지 않습니다. 가상이 필요하고 다이아몬드가 없습니다.
'programing' 카테고리의 다른 글
파이썬 목록 이해-반복되는 평가를 피하고 싶다 (0) | 2021.01.14 |
---|---|
특정 문자 앞의 문자열의 마지막 부분을 얻는 방법은 무엇입니까? (0) | 2021.01.14 |
빛나는 R에 대한 툴팁? (0) | 2021.01.14 |
postgresql : 스키마 내의 테이블 이름을 바꾸는 방법 (0) | 2021.01.14 |
Windows에 cURL을 어떻게 설치합니까? (0) | 2021.01.14 |