7

w poniższym kodzie:lista wirtualnego dziedziczenie inicjator C++

class A 
{ 
public: 
    int x; 
    A(int x):x(x){} 
}; 

class B: public virtual A 
{ 
public: 
    B(int x):A(x){} 
}; 
class C: public virtual A 
{ 
public: 
    C(int x):A(x){} 
}; 
class D: public B, public C 
{ 
public: 
    D(int x):B(x++), C(x++), A(x++){} 
}; 

dwa pytania:

  1. Dlaczego muszę dodać A(...) w liście inicjatora D's?
  2. D(int x):B(x++), C(x++), A(x++){} i D(int x):A(x++), B(x++), C(x++){} oba dają taki sam wynik z cout<<D(10).x, dlaczego?

Odpowiedz

6

Dlaczego muszę dodać A (...) na liście inicjalizatorów D'?

Dzieje się tak dlatego, że podobiekty baz wirtualnych muszą zostać zainicjowane przed wszystkimi innymi podobiektami. Ponieważ A nie ma konstruktora domyślnego, należy jawnie zainicjować podobiekt wirtualny A w D i określić, z którego argumentu ma zostać zbudowany.

Po wykonaniu konstruktorów bazowych podobiektów B i C nie będą one miały obiektu podrzędnego A w celu zainicjowania (co zostało wykonane wcześniej). Dlatego argumenty, które przechodzą do konstruktora A, są nieistotne.

D(int x):B(x++), C(x++), A(x++){} i D(int x):A(x++), B(x++), C(x++){} obie dają ten sam wynik z cout<<D(10).x, dlaczego?

Jak wyjaśniono powyżej, dzieje się tak, ponieważ wirtualne podstawowe obiekty podporządkowane są w pierwszej kolejności inicjowane.

Ogólnie kolejność inicjowania podobiektów klasy nigdy nie zależy od kolejności, w jakiej pojawiają się na liście inicjalizacyjnej konstruktora. Zgodnie z pkt 12.6.2/10 o C++ 11 Standard:

w nie-przekazaniu konstruktora inicjalizacji przebiega w następującej kolejności:

- Pierwszy, a tylko dla konstruktora najbardziej pochodne klasy (1.8), wirtualnych klas bazowych są inicjowane w w kolejności, w jakiej pojawiają się na pierwszym od lewej do prawej przewodzie skierowanego acyklicznego wykresu klas bazowych, , gdzie "od lewej do prawej" jest kolejnością pojawiania się klas bazowych na liście pochodnej klasy bazowej.

- Następnie klasy bazowe bezpośrednie są inicjowane w celu deklaracji, które pojawiają się w base-specyfikującego liście (niezależnie od kolejności MEM-inicjalizatorów).

- Potem non-statyczne członkowie danych są inicjowane w kolejności, w jakiej zostały zadeklarowane w definicji klasy (ponownie, niezależnie od kolejności MEM-inicjalizatorów).

- Na końcu złożona instrukcja ciała konstruktora jest wykonywana.

1

Wirtualne klasy bazowe są inicjowane tylko przez najbardziej pochodną klasę. Oznacza to, że jeśli utworzysz instancję D w twoim przykładzie, A zostanie zainicjowane tylko przez jego pojawienie się na liście inicjalizatorów pamięci D. Jego pojawienie się na listach inicjujących pamięć B i C jest po prostu ignorowane.

Dlatego właśnie trzeba zainicjować A w D: A nie posiada domyślny konstruktor, więc D musi wiedzieć, jak go zainicjować.