Detaillierte Erläuterung der C++-Funktionsvererbung: Wie vermeide ich das Problem der „Diamantvererbung'?

WBOY
Freigeben: 2024-05-02 11:45:02
Original
549 Leute haben es durchsucht

Diamond-Vererbungsproblem: Das Problem tritt auf, wenn eine abgeleitete Klasse gleichzeitig dieselbe Funktion von mehreren Basisklassen erbt und nicht bestimmen kann, welche Funktionsversion aufgerufen werden soll. Lösung: Virtuelle Vererbung: Erstellen Sie einen virtuellen Tabellenzeiger der Basisklasse, um sicherzustellen, dass Funktionsaufrufe immer auf die spezifischste Basisklassenimplementierung verweisen. Praktischer Fall: Die Zylinderklasse erbt von Kreis und Rechteck, verwendet virtuelle Vererbung, um die Rautenvererbung zu vermeiden, und stellt sicher, dass die Funktionsimplementierung getArea () der Zylinderklasse immer aufgerufen wird.

C++ 函数继承详解:如何避免“钻石继承”问题?

C++-Funktionsvererbung Detaillierte Erklärung: Umgang mit „Diamantvererbung“

Einführung

Funktionsvererbung ist eine leistungsstarke Funktion in C++, die es abgeleiteten Klassen ermöglicht, auf Funktionen der Basisklasse zuzugreifen und diese wiederzuverwenden. Wenn jedoch mehrere Basisklassen dieselben Funktionen haben, kann ein Problem namens „Diamantvererbung“ auftreten. In diesem Artikel werden die Diamantenvererbung und ihre Lösungen erörtert und praktische Fälle vorgestellt.

Diamant-Vererbung

Diamant-Vererbung tritt auf, wenn eine abgeleitete Klasse gleichzeitig dieselbe Funktion von zwei oder mehr Basisklassen erbt. Dies führt dazu, dass nicht ermittelt werden kann, welche Funktionsversion in der abgeleiteten Klasse aufgerufen wurde.

class Base1 { public: void print() { std::cout << "Base1 print" << std::endl; } }; class Base2 { public: void print() { std::cout << "Base2 print" << std::endl; } }; class Derived : public Base1, public Base2 { public: void print() { // 调用哪个基类的 print() 函数? } };
Nach dem Login kopieren

Im obigen Beispiel erbt die KlasseDerivedvonBase1undBase2, beide Basisklassen haben die gleicheprint()Funktion. Beim Aufruf vonDerived::print()kann nicht ermittelt werden, obBase1::print()oderBase2::print()aufgerufen wurde .Derived类从Base1Base2继承,这两个基类都有相同的print()函数。当调用Derived::print()时,无法确定是否调用Base1::print()Base2::print()

避免钻石继承

避免钻石继承的一个常见解决方案是使用虚继承。虚继承会创建基类的虚表指针,而不是复制基类的对象。这确保了针对派生类的函数调用总是指向最具体的基类实现。

class Base1 { public: virtual void print() { std::cout << "Base1 print" << std::endl; } }; class Base2 { public: virtual void print() { std::cout << "Base2 print" << std::endl; } }; class Derived : public virtual Base1, public virtual Base2 { public: void print() override { std::cout << "Derived print" << std::endl; } };
Nach dem Login kopieren

在上面的示例中,Base1Base2使用了虚继承。这确保了Derived::print()将始终调用Derived类的实现。

实战案例

考虑一个计算图形面积的示例。我们有一个基类Shape,它定义了计算面积的getArea()函数。我们还有两个派生类CircleRectangle,它们提供形状特定的面积计算。

class Shape { public: virtual double getArea() = 0; }; class Circle : public Shape { public: Circle(double radius) : _radius(radius) {} double getArea() override { return 3.14 * _radius * _radius; } private: double _radius; }; class Rectangle : public Shape { public: Rectangle(double width, double height) : _width(width), _height(height) {} double getArea() override { return _width * _height; } private: double _width; double _height; };
Nach dem Login kopieren

为了实现“套筒”形状,我们创建了一个派生类Cylinder,它从CircleRectangle继承。然而,由于CircleRectangle都有getArea()函数,因此Cylinder将面临钻石继承问题。

class Cylinder : public Circle, public Rectangle { public: Cylinder(double radius, double height) : Circle(radius), Rectangle(radius, height) {} };
Nach dem Login kopieren

为了避免钻石继承,我们使用虚继承:

class Cylinder : public virtual Circle, public virtual Rectangle { public: Cylinder(double radius, double height) : Circle(radius), Rectangle(radius, height) {} };
Nach dem Login kopieren

现在,Cylinder类的getArea()函数总是调用它派生的最具体类(即Cylinder

Vermeidung der Diamanten-VererbungEine gängige Lösung zur Vermeidung der Diamanten-Vererbung ist die Nutzung der virtuellen Vererbung. Durch die virtuelle Vererbung wird ein vtable-Zeiger auf die Basisklasse erstellt, anstatt das Basisklassenobjekt zu kopieren. Dadurch wird sichergestellt, dass Funktionsaufrufe an eine abgeleitete Klasse immer auf die spezifischste Basisklassenimplementierung verweisen. rrreeeIm obigen Beispiel verwenden Base1und Base2virtuelle Vererbung. Dadurch wird sichergestellt, dass Derived::print()immer die Implementierung der Klasse Derivedaufruft. Praktischer FallBetrachten Sie ein Beispiel für die Berechnung der Fläche eines Diagramms. Wir haben eine Basisklasse Shape, die die Funktion getArea()zur Flächenberechnung definiert. Wir haben auch zwei abgeleitete Klassen, Circleund Rectangle, die formspezifische Flächenberechnungen ermöglichen. rrreeeUm die „Ärmel“-Form zu implementieren, haben wir eine abgeleitete Klasse Cylindererstellt, die von Circleund Rectangleerbt. Da jedoch Circleund Rectanglebeide über getArea()-Funktionen verfügen, wird Cylindermit Diamantvererbungsproblemen konfrontiert sein. rrreeeUm die Rautenvererbung zu vermeiden, verwenden wir die virtuelle Vererbung: rrreeeJetzt ruft die Funktion getArea()der Klasse Cylinderimmer die spezifischste Klasse auf, von der sie abgeleitet ist (d. h. Zylinder) Implementierung.

Das obige ist der detaillierte Inhalt vonDetaillierte Erläuterung der C++-Funktionsvererbung: Wie vermeide ich das Problem der „Diamantvererbung'?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage
Über uns Haftungsausschluss Sitemap
Chinesische PHP-Website:Online-PHP-Schulung für das Gemeinwohl,Helfen Sie PHP-Lernenden, sich schnell weiterzuentwickeln!