C++-Call-Basisklassenmethode

Abdul Mateen 12 Oktober 2023
  1. Vererbung in C++
  2. Probleme beim Aufrufen der Basisklassenmethode
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.

Verwandter Artikel - C++ Inheritance