C++-Call-Basisklassenmethode
In diesem Tutorial wird das Aufrufen der Methode der übergeordneten Klasse von einer untergeordneten Klasse mithilfe von C++ erläutert. Zuerst werden wir die Vererbung schnell aktualisieren.
Später werden wir das Aufrufen von Basisklassenmethoden in verschiedenen Szenarios und verwandte Probleme besprechen.
Vererbung in C++
Vererbung ist ein mächtiges Merkmal der objektorientierten Programmierung. Durch Vererbung können untergeordnete Klassen Attribute und Funktionen der übergeordneten Klasse gemeinsam nutzen, was die Wiederverwendbarkeit in OOP erleichtert.
Bei der Vererbung kommen zwei Klassen in eine Beziehung, die als Eltern-Kind-, Basis-abgeleitete oder verallgemeinerte-spezialisierte Beziehung bekannt ist; Am häufigsten wird jedoch ein von Basen abgeleiteter Jargon anstelle von Eltern und Kind verwendet.
Syntax der Vererbung in C++:
class Parent {
..
};
class Child : InheritanceSpecifier Parent {
...
};
Um eine abgeleitete Klasse zu erstellen, müssen wir InheritanceSpecifier
schreiben, gefolgt vom Namen der Basisklasse. Dabei kann der InheritanceSpecifier
public
, private
oder protected
sein.
Zudem kann die Vererbung mehrfach
erfolgen, wenn beim Vererben die Namen mehrerer Elternklassen angegeben werden. Mehr zu Erbarten finden Sie hier.
Wir werden im gesamten Artikel die öffentliche
Vererbung verwenden, um die Dinge einfach zu halten. Wir können Basisklassenmethoden (wenn nicht private
) innerhalb der untergeordneten Klasse und mit dem Objekt der untergeordneten Klasse aufrufen, wie im folgenden Code gezeigt.
class P {
public:
void pf() { cout << "Parent class function\n"; }
};
class C : public P {
public:
void cf() {
pf();
cout << "Child class function\n";
}
};
int main() {
C cObj;
cObj.cf();
cObj.pf();
return 0;
}
Wir haben eine übergeordnete Klasse P
erstellt, die öffentlich von der untergeordneten Klasse C
geerbt wird. Die Funktion cf()
in der Kindklasse C
ruft die Basismethode pf()
auf.
In ähnlicher Weise ruft im Treibercode (d. h. main()
) das untergeordnete Objekt cObj
die Basisklassenmethode direkt auf.
Ausgang:
Parent class function
Child class function
Parent class function
Das obige Beispiel war sehr trivial, um den Aufruf der Basisklassenfunktion zu verstehen: innerhalb der untergeordneten Klasse und mit dem Objekt der untergeordneten Klasse.
Komplexere Situationen erfordern jedoch möglicherweise zusätzliche Vorsicht beim Aufrufen der Basismethoden, wie in den folgenden Abschnitten erläutert.
Probleme beim Aufrufen der Basisklassenmethode
Es scheint kein Problem beim Aufrufen der Basisklassenmethode im vorherigen Code und in der vorherigen Ausgabe zu geben. Es treten jedoch einige verwandte Probleme auf, z. B. wenn die Eltern- und Kindklassen die gleiche Funktion haben oder das Kind zwei oder mehr Eltern hat, die die gleiche Funktion haben.
Lassen Sie uns diese Themen einzeln besprechen.
Elternteil und Kind haben die gleiche Funktion
Übergeordnete und untergeordnete Klassen können dieselben Funktionen haben, und in einigen Fällen möchten wir möglicherweise die Funktion der übergeordneten Klasse mit dem Objekt der untergeordneten Klasse aufrufen, oder wir möchten möglicherweise die Funktion der übergeordneten Klasse innerhalb der untergeordneten Klasse aufrufen.
Sehen wir uns zunächst den Code an, der das Szenario demonstriert.
class Parent {
public:
void f() { cout << "Parent class function\n"; }
};
class Child : public Parent {
public:
void f() { cout << "Child class function\n"; }
};
int main() {
Child cObj;
cObj.f();
return 0;
}
Ausgang:
Child class function
Beachten Sie hier, dass das Objekt der untergeordneten Klasse die Funktion f()
der untergeordneten Klasse aufruft (nicht von der übergeordneten Klasse). Um das f()
der übergeordneten Klasse über das Objekt der untergeordneten Klasse aufzurufen, müssen wir den Namen der übergeordneten Klasse mit dem Bereichsauflösungsoperator (::
) verwenden, wie im folgenden Code gezeigt.
class Parent {
public:
void f() { cout << "Parent class function\n"; }
};
class Child : public Parent {
public:
void f() { cout << "Child class function\n"; }
};
int main() {
Child cObj;
cObj.Parent::f(); // calling f() of parent class
cObj.f();
return 0;
}
Ausgang:
Parent class function
Child class function
Siehe die zweite Zeile in der Funktion main()
, wo wir den Namen der übergeordneten Klasse mit dem Bereichsauflösungsoperator verwendet haben. Entsprechend sehen wir in der ersten Zeile der Ausgabe die von f()
der übergeordneten Klasse ausgegebene Nachricht.
Die genaue Syntax sollte befolgt werden, um die Basisklassenfunktion innerhalb einer untergeordneten Klasse aufzurufen, wie im folgenden Code dargestellt.
class Parent {
public:
void f() { cout << "Parent class function\n"; }
};
class Child : public Parent {
public:
void f() {
Parent::f();
cout << "Child class function\n";
}
};
int main() {
Child cObj;
cObj.f();
return 0;
}
Ausgang:
Parent class function
Child class function
Mehrdeutigkeit bei Mehrfachvererbung
Das zweite Problem beim Aufrufen der Basisklassenmethode besteht darin, dass mehrere (zwei oder mehr) Elternklassen dieselbe Methode haben können. In diesem Fall verwirrt der Compiler die Auswahl einer bestimmten Basisklasse zum Aufrufen der Methode, da dieselbe Methode in mehreren Basisklassen vorhanden ist.
Sehen wir uns einen Code an, der Mehrdeutigkeiten zur Kompilierzeit für den Compiler erzeugt, während er eine bestimmte Basisklasse zum Aufrufen der Basismethode auswählt.
class P1 {
public:
void fun() { cout << "Fun from P1\n"; }
};
class P2 {
public:
void fun() { cout << "Fun from P2\n"; }
};
class C : public P1, public P2 {};
int main() {
C objC;
objC.fun();
return 0;
}
Hier wird die Klasse C
von zwei Basisklassen (d. h. P1
und P2
) geerbt, und beide Eltern haben eine fun()
-Methode mit derselben Signatur.
Wenn nun der Treibercode die Funktion fun()
durch das untergeordnete Objekt (objC
) aufruft, verwirrt er den Compiler bei der Auswahl der richtigen Basisklasse.
Schauen wir uns die Compiler-Meldung an.
base_class_3.cpp: In function ‘int main()’:
base_class_3.cpp:16:7: error: request for member ‘fun’ is ambiguous
objC.fun();
Die Meldung zeigt deutlich, dass der Compiler verwirrt ist. Auch hier ist die Lösung dieselbe, die darin besteht, den Klassennamen mit dem Bereichsauflösungsoperator zu verwenden.
Sehen Sie sich den Code und die zugehörige Ausgabe an.
class P1 {
public:
void fun() { cout << "Fun from P1\n"; }
};
class P2 {
public:
void fun() { cout << "Fun from P2\n"; }
};
class C : public P1, public P2 {};
int main() {
C objC;
objC.P1::fun();
objC.P2::fun();
return 0;
}
Ausgang:
Fun from P1
Fun from P2
Siehe Zeilen 2 und 3 in main()
, wo die Klassennamen P1
und P2
mit dem Bereichsauflösungsoperator verwendet werden. Folglich können Sie in der Ausgabe die Ausgabe beider Basisfunktionen sehen.