Technologieaustausch

C: Der Unterschied zwischen Zusammensetzung und Vererbung

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

Einführung in die Zusammensetzung und Vergleich mit der Vererbung

Was ist Kombination?
(1) Komposition bedeutet die Verwendung von Objekten mehrerer anderer Klassen als Mitglieder innerhalb einer Klasse.
(2) Verwenden Sie den Klassenbaum, um Fälle zu erklären
(3) Die Kombination ist auch eine Methode zur Wiederverwendung von Code, und ihr Wesen liegt darinStrukturEnthalten

#include <iostream>
#include <vector>
#include <string>

// Leaf 类
class Leaf {
public:
    Leaf(const std::string& color) : color_(color) {
        std::cout << "Leaf constructor called: " << color_ << std::endl;
    }

    ~Leaf() {
        std::cout << "Leaf destructor called: " << color_ << std::endl;
    }

    void display() const {
        std::cout << "Leaf color: " << color_ << std::endl;
    }

private:
    std::string color_;
};

// Branch 类
class Branch {
public:
    Branch(int length) : length_(length) {
        std::cout << "Branch constructor called: " << length_ << " cm" << std::endl;
    }

    ~Branch() {
        std::cout << "Branch destructor called: " << length_ << " cm" << std::endl;
    }

    void display() const {
        std::cout << "Branch length: " << length_ << " cm" << std::endl;
    }

private:
    int length_;
};

// Tree 类,包含 Leaf 和 Branch 对象
class Tree {
public:
    Tree(const std::string& leafColor, int branchLength) 
        : leaf_(leafColor), branch_(branchLength) {
        std::cout << "Tree constructor called" << std::endl;
    }

    ~Tree() {
        std::cout << "Tree destructor called" << std::endl;
    }

    void display() const {
        leaf_.display();
        branch_.display();
    }

private:
    Leaf leaf_;
    Branch branch_;
};

int main() {
    Tree tree("Green", 150);
    tree.display();
    return 0;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70

Fügen Sie hier eine Bildbeschreibung ein

Vergleich der Merkmale von Vererbung und Zusammensetzung
(1) Vererbung ist eine Art (Ist a) Die Beziehung ist transitiv und nicht symmetrisch.
(2) Die Kombination ist die Beziehung eines Teils von (hat a),
(3) Vererbung ist eine White-Box-Wiederverwendung. Da die Klassenvererbung es uns ermöglicht, die Implementierungsdetails der übergeordneten Klasse entsprechend unserer eigenen Implementierung zu überschreiben, ist die Implementierung der übergeordneten Klasse für die untergeordnete Klasse sichtbar.
(4) Die White-Box-Wiederverwendungsfunktion der Vererbung zerstört die Kapselungsfunktion der Klasse bis zu einem gewissen Grad, da dadurch die Implementierungsdetails der übergeordneten Klasse der Unterklasse zugänglich gemacht werden.
(5) Die Kombination gehört zur Black-Box-Wiederverwendung.Die internen Details des enthaltenen Objekts sind für die Außenwelt unsichtbar, daher ist seine Kapselung relativ gut und die gegenseitige Abhängigkeit bei der Implementierung relativ gering.
(6) Die in der Kombination enthaltene Klasse wird erstellt und zerstört, während die enthaltende Klasse erstellt wird. Kombinationen sind Black-Box-Wiederverwendung und können zur Laufzeit dynamisch definiert werden, indem andere Objektreferenzen oder Zeiger desselben Typs abgerufen werden. Der Nachteil besteht darin, dass zu viele Objekte im System vorhanden sind.
(7) Das OO-Designprinzip besteht darin, zuerst zu kombinieren und dann zu erben.

Mehrfachvererbung und ihre Mehrdeutigkeitsprobleme

Mehrfachvererbung
(1) Mehrfachvererbung bedeutet, dass eine Unterklasse mehrere übergeordnete Klassen hat
(2)Demonstration der Mehrfachvererbung
(3) Es gibt keinen offensichtlichen Unterschied zwischen den Grundsätzen der Mehrfachvererbung und der Einzelvererbung.
(4) Mehrfachvererbung kann zu Mehrdeutigkeitsproblemen führen
Die Mehrdeutigkeit der Mehrfachvererbung 1
(1) Szenario: C verfügt über eine mehrfache Vererbung von A und B, sodass es zu Mehrdeutigkeiten kommt, wenn Mitglieder mit den gleichen Namen von A und B in C aufgerufen werden.
(2) Grund: C erbt ein Mitglied mit demselben Namen (unterschiedliche Namespace-Domäne) von A und B, sodass der Compiler beim Aufruf mit einem Objekt von C nicht bestimmen kann, welches wir aufrufen möchten.
(3) Lösung 1: Um das Auftreten zu vermeiden, sorgen Sie dafür, dass die Benennung der öffentlichen Mitglieder von A und B nicht wiederholt in Konflikt gerät. Aber das ist manchmal unkontrollierbar.
(4) Lösung 2: Geben Sie beim Codieren klar an, welche aufgerufen werden soll. Verwenden Sie cA::func (), um eindeutig anzugeben, dass die Funktion von Klasse A anstelle der Funktion von Klasse B aufgerufen wird.
(5) Lösung 3: Definieren Sie die Funktion in C neu. Dann wird die Funktion in C aufgerufen und die Funktion in A und B ausgeblendet.
(6) Zusammenfassung: Es kann gelöst werden, aber es gibt keine gute Lösung.

Die Mehrdeutigkeit der Mehrfachvererbung 2
(1) Szenario: Diamantenvererbungsproblem.Das heißt, A ist die Vorgängerklasse B1:A, B2:A, C:B1, B2. Zu diesem Zeitpunkt besteht Unklarheit, wenn das Objekt von C zum Aufrufen einer Methode in A verwendet wird.
(2) Analyse: c.func() ist mehrdeutig, cA::func() ist ebenfalls mehrdeutig, aber c.B1::func() und c.B2::func() sind nicht mehrdeutig
(3) Lösung: Wie Problem 1, Problem 2 ist jedoch subtiler und schwerer zu vermeiden

Fügen Sie hier eine Bildbeschreibung ein

// 祖类
class Aa {
 public:
  void show() { std::cout << "A's method" << std::endl; }
};

// 派生类 B1 和 B2,从 A 继承
class B1 : public Aa {
 public:
  void show() { std::cout << "B1's show" << std::endl; }
  void showB1() { std::cout << "B1's method" << std::endl; }
};

class B2 : public Aa {
 public:
  void show() { std::cout << "B2's show" << std::endl; }
  void showB2() { std::cout << "B2's method" << std::endl; }
};

// 派生类 C,从 B1 和 B2 继承
class C : public B1, public B2 {
 public:
  void showC() { std::cout << "C's method" << std::endl; }
};

int test070103() {
  C c;
  // c.Aa::show();    // 调用 A 的方法 不可以
  c.Aa::B1::show();  // 调用 A 的方法 不可以
  c.B2::Aa::show();  // 调用 A 的方法 不可以
  c.B1::show();      // 调用 B1 的方法
  c.B2::show();      // 调用 B2 的方法
  c.showB1();        // 调用 B1 的方法
  c.showB2();        // 调用 B2 的方法
  c.showC();         // 调用 C 的方法
  return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

Die virtuelle Vererbung löst das Mehrdeutigkeitsproblem der Diamantenvererbung

So nutzen Sie die virtuelle Vererbung
(1) Szenario: Diamantvererbung führt zu Mehrdeutigkeitsproblemen. Im Wesentlichen sind in B1 und B2 zwei A-Objekte in der Enkelklasse C enthalten, sodass Mehrdeutigkeit besteht.
(2) Virtuelle Vererbungslösung: Lassen Sie B1 und B2 A virtuell erben, und dann kann C B1 und B2 normal erben.
(3) So einfach ist die virtuelle Vererbung. Sie wurde entwickelt, um das Mehrdeutigkeitsproblem der Diamantvererbung zu lösen. Sie hat keine direkte Beziehung zu virtuellen Funktionen (um polymorphe Merkmale zu erreichen).

Das Implementierungsprinzip der virtuellen Vererbung
(1) Das Prinzip der virtuellen Vererbung lautet: virtueller Basisklassentabellenzeiger vbptr und virtuelle Basisklassentabelle virtuelle Tabelle
(2)Referenz:https://blog.csdn.net/xiejingfa/article/details/48028491

Fügen Sie hier eine Bildbeschreibung ein

Zusammenfassen

Verstehen Sie, was eine Kombination ist. Es gibt viele Mitgliedsvariablen anderer Klassentypen in einer Klassenklasse.
Verstehen Sie den Unterschied zwischen Zusammensetzung und Vererbung
Mehrdeutigkeit: Wenn Sie eine Funktion ausführen, ist es möglicherweise nicht unbedingt die Funktion, die Sie angeben möchten.
Lösung: Verwenden Sie cA::func(), um die aufgerufene Klasse explizit anzugeben
Die virtuelle Vererbung ähnelt einer bedingten Kompilierung. Sie muss nur einmal eingeführt werden. Sie muss nicht wiederholt eingeführt werden, um den Einführungseffekt zu erzielen.

Studienunterlagen und Verstoßkontakte werden gelöscht.
Quelle: Klassenzimmer für das Internet der Dinge von Lehrer Zhu