Zwei oder drei Dinge zur C++-Vererbung

Erbschaftsdefinition

Der Vererbungsmechanismus stellt das wichtigste Mittel der objektorientierten Programmierung dar, um Code wiederverwendbar zu machen, und ermöglicht es Programmierern, Funktionen auf der Grundlage der Beibehaltung der Eigenschaften der ursprünglichen Klasse zu erweitern und hinzuzufügen, um so neue Klassen zu erzeugen, die als abgeleitete Klassen bezeichnet werden

Vererbung ist eine Beziehung von a, die Unterklasse (abgeleitete Klasse) erbt die Elternklasse (Basisklasse), und die Unterklasse hat die gleichen Eigenschaften wie die Elternklasse:

所以子类可以使用父类的方法,父类的成员变量也拷贝到了子类!

Definieren Sie das Format

     派生类  继承方式   基类 

Klasse Unterklasse: öffentliche Elternklasse {}

Nachlass

Bildbeschreibung hier einfügen
Berechtigung: public>protected>private
Die Berechtigung der übergeordneten Klasse und die Berechtigung der Vererbungsmethode erfordern die Mindestberechtigung, die die Mitgliedsberechtigung der Unterklasse ist

Die Öffentlichkeit kann auf
die geschützte Klasse zugreifen und kann nicht darauf zugreifen, aber die Unterklasse kann auf
die private Klasse zugreifen und kann nicht darauf zugreifen, und die Unterklasse kann sie nicht sehen.

Unsichtbar:
Das "Member" in der Elternklasse wird immer noch in die Unterklasse kopiert, und die Unterklasse kann nicht darauf zugreifen, aber es gibt ein Gedächtnis in der Unterklasse

Konvertierung von Objektzuweisungen von Basisklassen und abgeleiteten Klassen

Dieser Teil ist der wichtigste Teil der Vererbung. Wenn ich diesen Teil nicht vollständig verstehe, muss es Probleme mit der Vererbung geben, und Polymorphismus muss verwechselt werden
. Lassen Sie mich mein persönliches Verständnis erklären. Wenn es irgendwelche Probleme gibt, korrigieren Sie mich bitte.

1. Die Basisklasse kann nicht der abgeleiteten Klasse zugewiesen werden
. 2. Das Objekt der abgeleiteten Klasse kann dem Objekt/Zeiger/Referenz der Basisklasse zugewiesen werden, es gibt ein Bild namens Slice oder Cut

1:
Die in der Basisklasse enthaltenen Member müssen kleiner oder gleich der abgeleiteten Klasse sein. Das ist ähnlich wie bei der Zuweisung des this-Zeigers der Klasse und des Objekts. Nur die Berechtigungen dürfen reduziert werden, und die Berechtigungen sind es darf nicht ausgebaut werden.

2:
① Die abgeleitete Klasse weist das Objekt der Basisklasse zu

#include<iostream>
using namespace std;
class A
{
    
    
public:
	void show()//切片
	{
    
    
		cout << _age << endl;
	}
protected:
	int _age=10;
};
class B :public A
{
    
    
public:
	int _num;
};
int main()
{
    
    
	B b;//派生类
	A a=b;//基类
}

Bildbeschreibung hier einfügen
Es ist ersichtlich, dass die abgeleitete Klasse A erbt, und es gibt
eine Kürzung (Slicing), wenn die abgeleitete Klasse der Basisklasse mit einem eindeutigen Member _num zugewiesen wird

a eine bestimmte Klasse ist, wird ein weiterer Raum für das übergeordnete Klassenobjekt geöffnet (dies wird im Polymorphismusprinzip verwendet) und die Mitglieder der übergeordneten Klasse in die abgeleitete Klasse kopiert, der virtuelle Funktionszeiger wird nicht kopiert. a ist eine konkrete Klasse mit einem virtuellen Funktionszeiger, der nur für A gilt

②Der Zeiger/die Referenz, die von der abgeleiteten Klasse der Basisklasse zugewiesen wurde

In diesem Fall zeigt der Zeiger auf den Teil der abgeleiteten Klasse, der der Elternklasse gemeinsam ist

So:
Bildbeschreibung hier einfügen
Der Zeiger und die Referenz können nur auf die öffentlichen Teile der Elternklasse und nur auf die geerbten Mitglieder der Elternklasse zugreifen

#include<iostream>
using namespace std;
class A
{
    
    
public:
	//A:this *= B:this*;
	void show()//切片
	{
    
    
		cout << _age << endl;
	}
protected:
	int _age=10;
};
class B :public A
{
    
    
	
public:

	int _age = 20;
	int _num;
};
int main()
{
    
    
	//1
	B b1;
	b1.show();
	//2
	A* a1 = &b1;
	a1->show();
	//3
	A& a2 = b1;
	a2.show();
	
	return 0;
}

Die interne Struktur von b1,a1
Bildbeschreibung hier einfügen

Nachdem b1 instanziiert wurde, ruft b1 die Show-Funktion auf, und die abgeleitete Klasse kann die Funktion der übergeordneten Klasse aufrufen. Zu diesem Zeitpunkt ist der this-Zeiger der übergeordneten Klasse = der this-Zeiger der untergeordneten Klasse, und das Slicing-Verhalten tritt auf. und auf diesen Zeiger kann nur von der Elternklasse aus zugegriffen werden, Down-Mitglieder können nicht auf die eindeutigen Mitglieder der Unterklasse zugreifen

Darüber hinaus haben Unterklassen und Oberklassen eindeutige Gültigkeitsbereiche. Es gibt Mitglieder mit demselben Namen in Unter- und Oberklassen. Unterklassenmitglieder blockieren den direkten Zugriff auf Mitglieder mit demselben Namen durch die Oberklasse. Diese Situation wird als Verstecken bezeichnet, auch als Neudefinition bezeichnet.

Aus der obigen Abbildung können wir also sehen, dass es zwei _ages in b1 gibt, das von A geerbte ist gleich 10 und das neu definierte ist gleich 20, sodass die von der übergeordneten Klasse geerbte 10 gedruckt wird.

Ebenso treten 2 und 3 auch als Slices auf, und der Zeiger zum Aufruf der Funktion kann nur auf die von der Basisklasse geerbten Member statt auf die neu definierten 20 zugreifen

Operationsergebnis:
Bildbeschreibung hier einfügen

Wenn wir dann Klasse B ändern, wird im ersten Schritt 20 ausgegeben,
Bildbeschreibung hier einfügen
Bildbeschreibung hier einfügen

Da die übergeordnete Klasse 10 erbt, ändern Sie die übergeordnete Klasse im Konstruktor so, dass sie 20 erbt

Diamant Erbe

Einfachvererbung und Mehrfachvererbung:

Einfachvererbung: Wenn eine Unterklasse nur eine direkte Elternklasse hat, wird die Vererbungsbeziehung als Einfachvererbung bezeichnet
Bildbeschreibung hier einfügen

Mehrfachvererbung: Wenn eine Unterklasse zwei oder mehr direkte Elternklassen hat, wird die Vererbungsbeziehung als Mehrfachvererbung bezeichnet.
Bildbeschreibung hier einfügen
Diamantvererbung: Diamantvererbung ist ein Sonderfall der Mehrfachvererbung
Bildbeschreibung hier einfügen

Das Problem mit der Vererbung von Diamanten (Grube)

#include<iostream>
using namespace std;
class A
{
    
    
public:
	int _a;
};
class B :public A
{
    
    
public:
	int _b;
};
class C :public A
{
    
    
public:
	int _c;
};
class D :public B, public C
{
    
    
	int _d;
};
int main()
{
    
    
	D d;
	//d._a = 10; 二义性编译器不知道调用从B还是C中继承而来的_a
	
	return 0;
}

Klassenzugehörigkeitsmodell von d:
Bildbeschreibung hier einfügen

Bildbeschreibung hier einfügen

Es ist ersichtlich, dass D _a von B und _a von C erbt, was zu Datenredundanz führt.Wenn
wir auf d._a zugreifen, weiß der Compiler nicht, auf welches _a er zugreifen soll, was zu Mehrdeutigkeit führt

Wenn es auf folgende Weise gelöst wird:
Bildbeschreibung hier einfügen
Bildbeschreibung hier einfügen
Obwohl auf _a zugegriffen werden kann, indem der Bereich angegeben wird, kann die Mehrdeutigkeit gelöst werden, aber die Redundanz kann nicht gelöst werden.Eine Klasse hat zwei Kopien derselben Mitgliedsvariablen, was nicht zulässig ist

Um dieses Problem zu lösen
, wird die virtuelle Vererbung vorgeschlagen (sie hat nichts mit virtuellen Funktionen zu tun).
Bildbeschreibung hier einfügen

#include<iostream>
using namespace std;
class A
{
    
    
public:
	int _a;
};
class B :virtual public A
{
    
    
public:
	int _b;
};
class C :virtual public A
{
    
    
public:
	int _c;
};
class D :public B, public C
{
    
    
	int _d;
};
int main()
{
    
    
	D d;
	d._a = 20;
	cout << d._a << endl;
	d.B::_a = 10;
	cout << d.B::_a << endl;
	return 0;
}

Nachdem das Programm d._a=20
Bildbeschreibung hier einfügen
aus dem Überwachungsfenster ausgeführt hat:
Nach der virtuellen Vererbung können Sie sehen, dass _a in d gleichzeitig zugewiesen ist , es keine Mehrdeutigkeit und keine Redundanz gibt, was nur einer entspricht Stück Daten

Wie C++-Compiler die Mehrdeutigkeit und Redundanz der virtuellen Vererbung lösen

Sie können die reale Situation durch das Monitorfenster nicht wirklich sehen, der Compiler wurde verarbeitet, also
können Sie es durch das Speicherfenster sehen

①: Es handelt sich nicht um eine virtuelle Vererbung Es gibt zwei Adressen von _a
Bildbeschreibung hier einfügen
Bildbeschreibung hier einfügen
in der gewöhnlichen Rautenvererbung ② Die Situation der virtuellen Vererbung

Bitte Bildbeschreibung hinzufügen
Bildbeschreibung hier einfügen

_a wird unten platziert

Bei der virtuellen Vererbung teilen sich zwei _a eine Adresse, wodurch Datenredundanz und Mehrdeutigkeit beseitigt werden

Aber es gibt zwei weitere Datenzeilen in den B- und C-Bereichen, diese Zeile ist genau vier Bytes groß

Es ist leicht, sich einen Zeiger vorzustellen, also worauf zeigt er?
Lassen Sie mich Sie zur Recherche mitnehmen

Virtuelle Basistabelle:
Bildbeschreibung hier einfügen
Es ist ersichtlich, dass die nächste Position, auf die gezeigt wird, 20, 12 ist, was den Offsets der Zeiger
(Zeiger der virtuellen Basistabelle) in B bzw. C zu der gemeinsamen Basisklasse _a entspricht

Was nützt das also?

D d;
B b=d;
C c=d;

Auf diese Weise werden b, c in Scheiben geschnitten, und dieser Offset wird benötigt, um das gemeinsame _a zu finden.

Die erste Zeile ist komplett Null, das ist der Offset, der für die polymorphe virtuelle Tabelle reserviert ist (Polymorphismus wird wieder eingeführt).

Supongo que te gusta

Origin blog.csdn.net/hbbfvv1h/article/details/120959839
Recomendado
Clasificación