Condivisione della tecnologia

C: La differenza tra composizione ed ereditarietà

2024-07-12

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

Introduzione alla composizione e confronto con l'ereditarietà

cos'è la combinazione
(1) Composizione significa utilizzare oggetti di più altre classi come membri all'interno di una classe.
(2) Utilizzare l'albero delle classi per spiegare i casi
(3) La combinazione è anche un metodo di riutilizzo del codice e la sua essenza lo èStrutturaIncludere

#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

Inserisci qui la descrizione dell'immagine

Confronto delle caratteristiche di ereditarietà e composizione
(1)L'ereditarietà è una sorta di (È a) La relazione è transitiva e non simmetrica.
(2) La combinazione è la relazione di una parte di (ha a),
(3) L'ereditarietà è il riutilizzo della scatola bianca. Poiché l'ereditarietà della classe ci consente di sovrascrivere i dettagli di implementazione della classe genitore in base alla nostra implementazione, l'implementazione della classe genitore è visibile alla classe figlia.
(4) La funzionalità di riutilizzo dell'ereditarietà white-box distrugge in una certa misura la funzionalità di incapsulamento della classe, poiché esporrà i dettagli di implementazione della classe genitore alla sottoclasse.
(5) La combinazione appartiene al riutilizzo della scatola nera.I dettagli interni dell'oggetto contenuto sono invisibili al mondo esterno, quindi il suo incapsulamento è relativamente buono e l'interdipendenza nell'implementazione è relativamente piccola.
(6) La classe inclusa nella combinazione verrà creata e distrutta quando viene creata la classe che la contiene. Le combinazioni sono riutilizzabili in scatola nera e possono essere definite dinamicamente in fase di esecuzione ottenendo altri riferimenti a oggetti o puntatori dello stesso tipo. Lo svantaggio è che ci sono troppi oggetti nel sistema.
(7) Il principio di progettazione OO è prima combinare e poi ereditare.

L'ereditarietà multipla e i suoi problemi di ambiguità

eredità multipla
(1) Ereditarietà multipla significa che una sottoclasse ha più classi genitore
(2)Dimostrazione dell'ereditarietà multipla
(3) Non esiste alcuna differenza evidente tra i principi dell'ereditarietà multipla e dell'eredità unica.
(4) L'ereditarietà multipla può portare a problemi di ambiguità
L'ambiguità dell'ereditarietà multipla 1
(1) Scenario: C ha ereditarietà multipla da A e B, quindi ci sarà ambiguità quando si chiamano membri con gli stessi nomi di A e B in C.
(2) Motivo: C eredita un membro con lo stesso nome (dominio dello spazio dei nomi diverso) da A e B, quindi quando si chiama con un oggetto di C, il compilatore non può determinare quale vogliamo chiamare.
(3) Soluzione 1: per evitare che ciò accada, evitare che i nomi dei membri pubblici di A e B entrino ripetutamente in conflitto. Ma questo a volte è incontrollabile.
(4) Soluzione 2: specificare chiaramente quale chiamare durante la codifica, utilizzare cA::func() per specificare chiaramente che viene chiamata la func della classe A anziché la func della classe B.
(5) Soluzione 3: ridefinire func in C, quindi verrà chiamata la funzione in C e la funzione in A e B verrà nascosta.
(6) Riepilogo: può essere risolto, ma non esiste una buona soluzione.

L'ambiguità dell'ereditarietà multipla 2
(1) Scenario: problema dell'eredità dei diamanti.Cioè, A è la classe antenata, B1:A, B2:A, C:B1,B2 In questo momento, ci sarà ambiguità quando si utilizza l'oggetto di C per chiamare un metodo in A.
(2) Analisi: c.func() è ambiguo, anche cA::func() è ambiguo, ma c.B1::func() e c.B2::func() non sono ambigui
(3) Soluzione: come il problema 1, ma il problema 2 è più subdolo e più difficile da evitare

Inserisci qui la descrizione dell'immagine

// 祖类
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

L'ereditarietà virtuale risolve il problema dell'ambiguità dell'eredità dei diamanti

Come utilizzare l'ereditarietà virtuale
(1) Scenario: l'ereditarietà del diamante porta a problemi di ambiguità Essenzialmente, ci sono due oggetti A contenuti in B1 e B2 nella classe nipote C, quindi c'è ambiguità.
(2) Soluzione di ereditarietà virtuale: lascia che B1 e B2 ereditino virtualmente A, quindi C può ereditare B1 e B2 normalmente.
(3) L'ereditarietà virtuale è così semplice. È stata creata per risolvere il problema dell'ambiguità dell'ereditarietà del diamante. Non ha alcuna relazione diretta con le funzioni virtuali (per ottenere caratteristiche polimorfiche).

Il principio di implementazione dell'ereditarietà virtuale
(1) Il principio dell'ereditarietà virtuale è: puntatore della tabella della classe base virtuale vbptr e tabella virtuale della tabella della classe base virtuale
(2)Riferimento:Italiano: https://blog.csdn.net/xiejingfa/article/details/48028491

Inserisci qui la descrizione dell'immagine

Riassumere

Comprendere cos'è la combinazione. In una classe sono presenti molte variabili membro di altri tipi di classe.
Comprendere la differenza tra composizione ed ereditarietà
Ambiguità: se esegui una funzione, potrebbe non essere necessariamente quella che desideri specificare.
Soluzione: utilizzare cA::func() per specificare esplicitamente la classe da chiamare
L'ereditarietà virtuale è un po' come la compilazione condizionale: deve essere introdotta una sola volta per ottenere l'effetto di introduzione.

I registri degli studi e i contatti di violazione verranno eliminati.
Fonte: Aula sull’Internet delle cose dell’insegnante Zhu