Nyheter i Android, Telefoner, Prylar Och Recensioner

Vad är diamantproblemet i C++? Hur man hittar det och hur man fixar det

Multipelarv i C++ är kraftfullt, men ett knepigt verktyg som ofta leder till problem om det inte används försiktigt – problem som Diamond Problem.

I den här artikeln kommer vi att diskutera diamantproblemet, hur det uppstår från multipelt arv och vad du kan göra för att lösa problemet.

Multipelt arv i C++

Multiple Inheritance är en funktion i Object-Oriented Programming (OOP) där en underklass kan ärva från mer än en superklass. Med andra ord kan en barnklass ha mer än en förälder.

Figuren nedan visar en bildrepresentation av flera arv.

I diagrammet ovan, klass C har klass A och klass B som sina föräldrar.

Om vi ​​betraktar ett verkligt scenario, ärver ett barn från sin far och mor. Så ett barn kan representeras som en härledd klass med “Far” och “Mor” som sina föräldrar. På samma sätt kan vi ha många sådana verkliga exempel på multipelt arv.

Vid multipelarv exekveras konstruktörerna av en ärvd klass i den ordning som de ärvs. Å andra sidan avrättas förstörare i omvänd ordning av deras arv.

Låt oss nu illustrera det multipla arvet och verifiera ordningen för konstruktion och förstörelse av föremål.

Kodillustration av multipelarv

För multipelarvsillustrationen har vi exakt programmerat ovanstående representation i C++. Koden för programmet finns nedan.

#include<iostream>
using namespace std;
class A //base class A with constructor and destructor
{
public:
A() { cout << "class A::Constructor" << endl; }
~A() { cout << "class A::Destructor" << endl; }
};
class B //base class B with constructor and destructor
{
public:
B() { cout << "class B::Constructor" << endl; }
~B() { cout << "class B::Destructor" << endl; }
};
class C: public B, public A //derived class C inherits class A and then class B (note the order)
{
public:
C() { cout << "class C::Constructor" << endl; }
~C() { cout << "class C::Destructor" << endl; }
};
int main(){
C c;
return 0;
}

Resultatet vi får från ovanstående program är följande:

class B::Constructor
class A::Constructor
class C::Constructor
class C::Destructor
class A::Destructor
class B::Destructor

Om vi ​​nu kontrollerar utgången ser vi att konstruktörerna anropas i ordning B, A och C medan destruktörerna är i omvänd ordning. Nu när vi känner till grunderna för multipelt arv går vi vidare för att diskutera diamantproblemet.

Relaterad  Microsoft Edge kommer snart att erbjuda en minimeny och en bättre lösenordsövervakning

Diamantproblemet, förklarat

Diamantproblemet uppstår när en barnklass ärver från två föräldraklasser som båda delar en gemensam farförälderklass. Detta illustreras i diagrammet nedan:

Här har vi en klass Barn ärver från klasser Far och Mor. Dessa två klasser ärver i sin tur klassen Person eftersom både far och mor är person.

Som visas i figuren ärver klassbarn egenskaperna hos klassperson två gånger – en gång från far och igen från mor. Detta ger upphov till tvetydighet eftersom kompilatorn inte förstår vilken väg den ska gå.

Detta scenario ger upphov till en diamantformad arvsgraf och kallas känd som “Diamondproblemet”.

Kodillustration av diamantproblemet

Nedan har vi representerat ovanstående exempel på diamantformat arv programmatiskt. Koden ges nedan:

#include<iostream>
using namespace std;
class Person { //class Person
public:
Person(int x) { cout << "Person::Person(int) called" << endl; }
};

class Father : public Person { //class Father inherits Person
public:
Father(int x):Person(x) {
cout << "Father::Father(int) called" << endl;
}
};

class Mother : public Person { //class Mother inherits Person
public:
Mother(int x):Person(x) {
cout << "Mother::Mother(int) called" << endl;
}
};

class Child : public Father, public Mother { //Child inherits Father and Mother
public:
Child(int x):Mother(x), Father(x) {
cout << "Child::Child(int) called" << endl;
}
};

int main() {
Child child(30);
}

Följande är resultatet av detta program:

Person::Person(int) called
Father::Father(int) called
Person::Person(int) called
Mother::Mother(int) called
Child::Child(int) called

Nu kan du se oklarheten här. Klasskonstruktorn Person anropas två gånger: en gång när klassobjektet Father skapas och nästa när klassobjektet Moder skapas. Egenskaperna för klassen Person ärvs två gånger, vilket ger upphov till tvetydighet.

Eftersom klasskonstruktorn Person anropas två gånger, kommer destruktorn också att anropas två gånger när klassobjektet Child förstörs.

Relaterad  Pittoresk trailer för äventyret Submerged: Hidden Depths. Spelet kommer att släppas på PC och konsoler i år.

Om du nu har förstått problemet korrekt, låt oss diskutera lösningen på diamantproblemet.

Hur man fixar diamantproblemet i C++

Lösningen på diamantproblemet är att använda virtuell nyckelord. Vi gör de två föräldraklasserna (som ärver från samma farförälderklass) till virtuella klasser för att undvika två kopior av farförälderklassen i barnklassen.

Låt oss ändra illustrationen ovan och kontrollera utdata:

Kodillustration för att åtgärda diamantproblemet

#include<iostream>
using namespace std;
class Person { //class Person
public:
Person() { cout << "Person::Person() called" << endl; } //Base constructor
Person(int x) { cout << "Person::Person(int) called" << endl; }
};

class Father : virtual public Person { //class Father inherits Person
public:
Father(int x):Person(x) {
cout << "Father::Father(int) called" << endl;
}
};

class Mother : virtual public Person { //class Mother inherits Person
public:
Mother(int x):Person(x) {
cout << "Mother::Mother(int) called" << endl;
}
};

class Child : public Father, public Mother { //class Child inherits Father and Mother
public:
Child(int x):Mother(x), Father(x) {
cout << "Child::Child(int) called" << endl;
}
};

int main() {
Child child(30);
}

Här har vi använt virtuell nyckelord när klasser far och mor ärver klassen Person. Detta brukar kallas “virtuellt arv”, vilket garanterar att endast en enda instans av den ärvda klassen (i det här fallet Person-klassen) förs vidare.

Med andra ord kommer klassen Child att ha en enda instans av klassen Person, som delas av både far- och moderklasserna. Genom att ha en enda instans av klassen Person löses tvetydigheten.

Utdata från ovanstående kod ges nedan:

Person::Person() called
Father::Father(int) called
Mother::Mother(int) called
Child::Child(int) called

Här kan du se att klassen Personkonstruktör bara anropas en gång.

En sak att notera om virtuellt arv är att även om den parametriserade konstruktorn för klassen Person uttryckligen anropas av klasskonstruktörer för Fader och Mother genom initialiseringslistor, endast baskonstruktorn för klassen Person kommer att anropas.

Detta beror på att det bara finns en enda instans av en virtuell basklass som delas av flera klasser som ärver från den.

Relaterad  Hur man ökar recensioner och betyg för ditt SAAS-företag

För att förhindra att baskonstruktorn körs flera gånger, anropas inte konstruktorn för en virtuell basklass av klassen som ärver från den. Istället anropas konstruktören av konstruktören av betongklassen.

I exemplet ovan anropar klassen Child direkt baskonstruktorn för klassen Person.

Vad händer om du behöver köra den parametriserade konstruktorn för basklassen? Du kan göra det genom att uttryckligen kalla det i barnklassen snarare än i far- eller morklasserna.

Diamantproblemet i C++, löst

Diamantproblemet är en tvetydighet som uppstår vid multipelt arv när två föräldraklasser ärver från samma farförälderklass, och båda förälderklasserna ärvs av en enda barnklass. Utan att använda virtuellt arv skulle barnklassen ärva farförälderklassens egenskaper två gånger, vilket leder till tvetydighet.

Detta kan dyka upp ofta i verklig kod, så det är viktigt att ta itu med den oklarheten när den upptäcks.

Diamantproblemet åtgärdas med hjälp av virtuellt arv, där virtuell nyckelord används när föräldraklasser ärver från en delad farförälderklass. Genom att göra det görs bara en kopia av farförälderklassen, och objektkonstruktionen av farförälderklassen görs av barnklassen.

Om författaren

Shilpa Nadkarni (1 artiklar publicerade)

Mer från Shilpa Nadkarni

Prenumerera på vårt nyhetsbrev

Gå med i vårt nyhetsbrev för tekniska tips, recensioner, free e-böcker och exklusiva erbjudanden!

Klicka här för att prenumerera

Table of Contents