2015-02-27 28 views
10

Należy wziąć pod uwagę poniższy kod. Zarówno g ++, jak i clang ++ narzekają (poprawnie), że konstruktor A(int) jest prywatny w klasie D. Zauważ, że jako A jest wirtualną klasą podstawową D, A należy zainicjować w inicjalizatorze pamięci klasy D, najbardziej pochodną klasą, zgodnie z §12.6.2/7 w C++ 11. Zobacz live example.Niejawne wywoływanie konstruktora niedostępnej wirtualnej klasy bazowej

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

class B : private virtual A { 
protected: 
    B(int i) : A(i) { } }; 

class C : public B, private virtual A { 
protected: 
    C(int i) : A(i), B(i) { } 
}; 

class D : public C { 
public: 
    D() : A(1), C(3) { } 
}; 

int main() { 
    D d; 
} 

Ale oba kompilatory nie przejmuj się tym, że konstruktor domyślny dla klasy A jest także prywatny w D, czyli zarówno skompilować i wykonać kod normalnie, jeśli definiujemy konstruktor dla D następująco:

D() : C(3) {} 

I to jest złe, o ile mogę powiedzieć.

Zauważ, że oba kompilatory nie skompilować (prawidłowo), jeżeli zdefiniujemy:

D() : A(), C(3) {} 
+0

Możesz dodać przykład na żywo, który pokazuje przypadek, w którym jesteś zaintrygowany, np. 'D(): C (3) {}' –

+0

@RSahu Nawet dla przypadku 'D(): C (3) {}' wskazał wyżej ? Pytam o to, ponieważ tak naprawdę nie wiem, jaka jest różnica między kompilatorem, którego użyłem w Coliru (standardowe std = C++ 11) i 4.7.3, o którym wspomniałeś powyżej – Belloc

+0

@RSahu z 'D(): C (3) ', nie otrzymuję błędu z GCC 4.7.4. Które opcje wiersza poleceń używasz z 4.7.3, aby uzyskać błąd? – hvd

Odpowiedz

9

But both compilers don't bother with the fact that the default constructor for class A is also private in D ,

Nie, że konstruktor domyślny nie jest prywatny. Klasa podstawowa A jest prywatna, ale jej domyślny konstruktor jest publiczny.

I dlatego to działa: gdy nazewnictwa klas bazowych w konstruktor-inicjatora, wymienieni klasy bazowe muszą być dostępne, ponieważ kontrola dostępu odnosi się do nazw, a kilka specjalne wyjątki gdzie średnia mówi, że niejawnie nazywa funkcje wciąż muszą być dostępne.

Gdy klasy bazowe są niejawnie konstruowane, te klasy bazowe nie są nazwane. Są po prostu domyślnie zainicjalizowane (na 12.6.2p8), a domyślna inicjalizacja sprawdza jedynie, czy konstruktor jest dostępny (za 8,5p7).

Można powiedzieć, że problem jest z nazwą klasy bazowej nie używając prywatnych odziedziczony nazwę klasy bazowej, ale za pomocą dostępnych globalnie nazwy ::A:

D() : ::A(1), C(3) { } 

Live example

+0

Domyślny konstruktor jest publiczny tylko wtedy, gdy nie jest dostarczany przez użytkownika. – Belloc

+0

@ Belloc To nie ma sensu. Przeczytaj ponownie swój komentarz, pomyśl o tym, co chcesz powiedzieć, a następnie ponownie go sformułuj. – hvd

+0

§12.1/5 (C++ 11) 'Domyślnie domyślny konstruktor jest wbudowanym elementem publicznym w swojej klasie. – Belloc