Moștenirea multiplă în C ++ este puternică, dar este un instrument dificil, care duce adesea la probleme dacă nu este utilizat cu atenție - probleme precum Diamond Problem.
În acest articol, vom discuta problema diamantului, modul în care apare din moștenirea multiplă și ce puteți face pentru a rezolva problema.
Moștenirea multiplă în C ++
Moștenirea multiplă este o caracteristică a programării orientate pe obiecte (OOP) unde o subclasă poate moșteni de la mai multe superclase. Cu alte cuvinte, o clasă de copii poate avea mai mulți părinți.
Figura de mai jos prezintă o reprezentare picturală a mai multor moșteniri.
În diagrama de mai sus, clasa C are clasa a și clasa B ca părinți ai săi.
Dacă luăm în considerare un scenariu din viața reală, un copil moștenește de la tată și mamă. Deci, un Copil poate fi reprezentat ca o clasă derivată cu „Tatăl” și „Mama” ca părinți. În mod similar, putem avea multe astfel de exemple reale de moștenire multiplă.
În moștenirea multiplă, constructorii unei clase moștenite sunt executați în ordinea în care sunt moșteniți. Pe de altă parte, distructorii sunt executați în ordinea inversă a moștenirii lor.
Acum să ilustrăm moștenirea multiplă și să verificăm ordinea de construcție și distrugere a obiectelor.
Cod Ilustrație a Moștenirii Multiple
Pentru ilustrarea moștenirii multiple, am programat exact reprezentarea de mai sus în C ++. Codul pentru program este dat mai jos.
#include
folosind spațiul de nume std;
clasa A // clasa de bază A cu constructor și destructor
{
public:
A () {cout << "clasa A:: Constructor" << endl; }
~ A () {cout << "clasa A:: Destructor" << endl; }
};
clasa B // clasa de bază B cu constructor și destructor
{
public:
B () {cout << "clasa B:: Constructor" << endl; }
~ B () {cout << "clasa B:: Destructor" << endl; }
};
clasa C: public B, public A // derivat clasa C moștenește clasa A și apoi clasa B (rețineți comanda)
{
public:
C () {cout << "clasa C:: Constructor" << endl; }
~ C () {cout << "clasa C:: Destructor" << endl; }
};
int main () {
C c;
retur 0;
}
Ieșirea pe care o obținem din programul de mai sus este următoarea:
clasa B:: Constructor
clasa A:: Constructor
clasa C:: Constructor
clasa C:: Destructor
clasa A:: Destructor
clasa B:: Destructor
Acum, dacă verificăm ieșirea, vedem că constructorii sunt numiți în ordinea B, A și C, în timp ce distructorii sunt în ordinea inversă. Acum, că știm elementele de bază ale moștenirii multiple, trecem la discuția despre problema diamantului.
Problema diamantului, explicată
Problema Diamantului apare atunci când o clasă copil moștenește de la două clase părinte care ambele împărtășesc o clasă comună de bunici. Acest lucru este ilustrat în diagrama de mai jos:
Aici avem o clasă Copil moștenind din clase Tată și Mamă. Aceste două clase, la rândul lor, moștenesc clasa Persoană pentru că atât Tatăl, cât și Mama sunt Persoane.
După cum se arată în figură, clasa Copil moștenește trăsăturile clasei Persoană de două ori - o dată de la Tată și din nou de la Mamă. Acest lucru dă naștere la ambiguitate, deoarece compilatorul nu reușește să înțeleagă ce cale să urmeze.
Acest scenariu dă naștere unui grafic de moștenire în formă de diamant și este numit faimos „Problema diamantului”.
Ilustrația codului problemei diamantului
Mai jos am reprezentat exemplul de mai sus al moștenirii în formă de diamant programat. Codul este dat mai jos:
#include
folosind spațiul de nume std;
clasă Persoană {// clasă Persoană
public:
Person (int x) {cout << "Person:: Person (int) called" << endl; }
};
clasa Tatăl: persoană publică {// clasa Tatăl moștenește persoana
public:
Tatăl (int x): Persoana (x) {
cout << "Tată:: Tată (int) numit" << endl;
}
};
clasa Mamă: persoană publică {// clasa Mamă moștenește Persoană
public:
Mama (int x): Persoana (x) {
cout << "Mother:: Mother (int) called" << endl;
}
};
clasa Copil: Tată public, mamă publică {// Copilul moștenește Tatăl și mama
public:
Copil (int x): mamă (x), tată (x) {
cout << "Copil:: Copil (int) numit" << endl;
}
};
int main () {
Copil copil (30);
}
Următorul este rezultatul acestui program:
Persoană:: Persoană (int) apelată
Tatăl:: Tatăl (int) a sunat
Persoană:: Persoană (int) apelată
Mama:: Mama (int) a sunat
Copil:: Copil (int) sunat
Acum puteți vedea ambiguitatea aici. Constructorul clasei Persoane este numit de două ori: o dată când se creează obiectul clasei Tată și apoi când se creează obiectul clasei Mamă. Proprietățile clasei Person sunt moștenite de două ori, dând naștere la ambiguitate.
Deoarece constructorul clasei Person este numit de două ori, distructorul va fi, de asemenea, apelat de două ori atunci când obiectul clasei Child este distrus.
Acum, dacă ați înțeles corect problema, să discutăm soluția la problema Diamond.
Cum se remediază problema Diamond în C ++
Soluția la problema diamantului este utilizarea virtual cuvânt cheie. Transformăm cele două clase părinte (care moștenesc din aceeași clasă a bunicilor) în clase virtuale pentru a evita două copii ale clasei bunicilor din clasa copil.
Să schimbăm ilustrația de mai sus și să verificăm rezultatul:
Ilustrație de cod pentru a remedia problema diamantului
#include
folosind spațiul de nume std;
clasă Persoană {// clasă Persoană
public:
Person () {cout << "Person:: Person () called" << endl; } // Constructor de bază
Person (int x) {cout << "Person:: Person (int) called" << endl; }
};
clasa Tatăl: persoana publică virtuală {// clasa Tatăl moștenește Persoana
public:
Tatăl (int x): Persoana (x) {
cout << "Tată:: Tată (int) numit" << endl;
}
};
clasa Mamă: persoană publică virtuală {// clasa Mamă moștenește Persoană
public:
Mama (int x): Persoana (x) {
cout << "Mother:: Mother (int) called" << endl;
}
};
clasa Copil: Tată public, mamă publică {// clasă Copil moștenește Tată și Mamă
public:
Copil (int x): mamă (x), tată (x) {
cout << "Copil:: Copil (int) numit" << endl;
}
};
int main () {
Copil copil (30);
}
Aici am folosit virtual cuvânt cheie atunci când clasele Tatăl și Mama moștenesc clasa Persoană. Aceasta se numește de obicei „moștenire virtuală”, ceea ce garantează transmiterea unei singure instanțe a clasei moștenite (în acest caz, clasa Person).
Cu alte cuvinte, clasa Copil va avea o singură instanță a clasei Persoană, împărtășită atât de clasa Tatăl, cât și de cea a Mamei. Având o singură instanță a clasei Person, ambiguitatea este rezolvată.
Ieșirea codului de mai sus este dată mai jos:
Persoana:: Persoana () a sunat
Tatăl:: Tatăl (int) a sunat
Mama:: Mama (int) a sunat
Copil:: Copil (int) sunat
Aici puteți vedea că constructorul clasei Person este apelat o singură dată.
Un lucru de remarcat despre moștenirea virtuală este că, chiar dacă constructorul parametrizat al Clasa persoană este numită în mod explicit de constructorii clasei Tată și Mamă prin inițializare liste, va fi numit doar constructorul de bază al clasei Person.
Acest lucru se datorează faptului că există doar o singură instanță a unei clase de bază virtuale care este partajată de mai multe clase care moștenesc de la ea.
Pentru a împiedica constructorul de bază să ruleze de mai multe ori, constructorul pentru o clasă de bază virtuală nu este apelat de clasa care moștenește de la aceasta. În schimb, constructorul este numit de constructorul clasei concrete.
În exemplul de mai sus, clasa Child numește direct constructorul de bază pentru clasa Person.
Legate de: Un ghid pentru începători la biblioteca de șabloane standard în C ++
Ce se întâmplă dacă trebuie să executați constructorul parametrizat al clasei de bază? Puteți face acest lucru apelându-l în mod explicit la clasa Copil, mai degrabă decât la clasa Tată sau Mama.
Problema diamantului în C ++, rezolvată
Problema Diamantului este o ambiguitate care apare în moștenirea multiplă atunci când două clase părinte moștenesc din aceeași clasă de bunici și ambele clase părinte sunt moștenite de o singură clasă copil. Fără a utiliza moștenirea virtuală, clasa copil ar moșteni proprietățile clasei bunicilor de două ori, ducând la ambiguitate.
Acest lucru poate apărea frecvent în codul din lumea reală, deci este important să abordăm această ambiguitate ori de câte ori este văzută.
Problema Diamond este rezolvată folosind moștenirea virtuală, în care virtual cuvântul cheie este utilizat atunci când clasele părintești moștenesc de la o clasă de bunici partajată. Procedând astfel, se face o singură copie a clasei bunicilor, iar construcția obiectului clasei bunicilor se face de către clasa copilului.
Doriți să învățați programarea, dar nu știți de unde să începeți? Aceste proiecte și tutoriale de programare pentru începători vă vor începe.
Citiți în continuare
- Programare
- Programare C
Aboneaza-te la newsletter-ul nostru
Alăturați-vă newsletter-ului pentru sfaturi tehnice, recenzii, cărți electronice gratuite și oferte exclusive!
Faceți clic aici pentru a vă abona