Dla drugiego pytania prawdopodobnie wynika to z tego, że nie jest ono domyślnie zdefiniowane jako . Jeśli konstruktor jest tylko domyślnie zadeklarowany, nie ma błędu. Przykład:
struct A { A(int); };
struct B : A { };
// goes fine up to here
// not anymore: default constructor now is implicitly defined
// (because it's used)
B b;
Na pierwsze pytanie - zależy to od nazwy używanej przez kompilator. Nie mam pojęcia, co średnia określa, ale ten kod jest prawidłowy, na przykład dlatego, że zewnętrzna nazwa klasy (zamiast odziedziczyła nazwę klasy) jest dostępny:
class A {};
class B: private virtual A {};
class C: public B { C(): ::A() { } }; // don't use B::A
Może standard jest underspecified w tym momencie. Będziemy musieli patrzeć.
Nie ma problemu z kodem. Ponadto istnieje wskazówka, że kod jest ważny. Obiekt podrzędny (wirtualny) jest domyślnie zainicjowany - nie ma tekstu, który sugeruje, że wyszukiwanie nazwy dla nazwy klasy odbywa się wewnątrz zakresu C
.Oto co mówi standardowe:
12.6.2/8
(C++ 0x)
Jeśli dana niestatyczny członek danych lub klasa bazowa nie jest nazwany przez MEM-inicjatora-id (w tym przypadku gdzie nie ma mem-inicjator-lista, ponieważ konstruktor ma konstruktor-inicjator), a jednostka nie jest wirtualna klasa podstawowa klasy abstrakcyjnej
[...] inaczej, podmiot domyślny przygotowanej
A C++ 03 ma podobny tekst (mniej czytelny tekst - po prostu mówi, że jego domyślny konstruktor jest wywoływany w jednym miejscu, a inny uzależnia go od tego, czy klasa jest POD). Aby kompilator domyślnie zainicjował obiekt podrzędny, wystarczy wywołać jego domyślny konstruktor - nie ma potrzeby sprawdzania najpierw nazwy klasy bazowej (to już wie, jaka baza jest uważana).
Rozważmy następujący kod, który na pewno ma być ważne, ale to nie powieść, jeśli to byłoby być zrobione (patrz 12.6.2/4
w C++ 0x)
struct A { };
struct B : virtual A { };
struct C : B, A { };
C c;
Jeśli konstruktor domyślny kompilator byłaby po prostu patrzeć -up class name A
wewnątrz C
, miałoby to niejednoznaczny wynik wyszukiwania w odniesieniu do tego obiektu podrzędnego do zainicjowania, ponieważ znaleziono nie-wirtualne nazwy klas A
i wirtualne A
. Jeśli twój kod ma być źle sformułowany, powiedziałbym, że Standard musi zostać wyjaśniony.
Dla konstruktora, zauważyć co 12.4/6
mówi o destruktora C
:
Wszystkie destruktory nazywane są tak, jakby były odniesione z kwalifikowanej nazwy, czyli pomijając ewentualne destruktory wirtualne nadrzędne w więcej klasach pochodnych.
ten można interpretować na dwa sposoby:
- wywołanie :: ~ A()
- nazywając :: A :: ~ A()
Wydaje mnie, że Standard jest tu mniej jasny. Drugi sposób sprawiłby, że byłby ważny (przez 3.4.3/6
, C++ 0x, ponieważ obie nazwy klasy A
są wyszukiwane w zasięgu globalnym), podczas gdy pierwsza sprawi, że będzie on nieważny (ponieważ zarówno A
znajdzie odziedziczone nazwy klas). Zależy to również od tego, pod jakim pojęciem zaczyna się wyszukiwanie (i uważam, że będziemy musieli użyć wirtualnego obiektu bazowego "podobiekt" jako punktu początkowego). Jeśli to idzie jak
virtual_base -> A::~A();
Wtedy będziemy bezpośrednio znaleźć wirtualną „nazwę klasy jako nazwa publiczną, ponieważ nie będzie musiał przejść przez pochodzących klasa baza zakresów i znaleźć nazwę jako niedostępne. Znowu rozumowanie jest podobne.Rozważmy:
struct A { };
struct B : A { };
struct C : B, A {
} c;
Jeśli destruktor po prostu zadzwonić this->A::~A()
, to połączenie nie będzie ważny z powodu niejednoznacznego wyniku przeglądowej z A
jako dziedziczną nazwy klasy (nie można odnosić się do każdej niestatyczny członków funkcji z bezpośredni obiekt klasy bazowej z zakresu C
, patrz 10.1/3
, C++ 03). Będzie musiał jednoznacznie identyfikować nazwy klas, które są zaangażowane, i musi zaczynać się od referencji podobiektowej klasy, takiej jak a_subobject->::A::~A();
.
Z g ++ 4.4 kompiluje. Chociaż nie byłem w stanie znaleźć autorytatywnego odniesienia, moim zdaniem jest to, że powinien się skompilować. Najbardziej wyprowadzona klasa 'C' może skonstruować podobiekt typu" A ". Zauważ, że istnieją implementacje do zamykania dziedziczenia oparte na połączeniu dziedziczenia 'private virtual' * razem * z prywatnym konstruktorem w' A' i dostępie przyznawanym 'B' przez przyjaźń. Wszystkie komplikacje byłyby niepotrzebne, gdyby wystarczyło tylko prywatne dziedziczenie wirtualne. –
@ DavidRodríguez-dribeas "_ Wszystkie komplikacje byłyby niepotrzebne, gdyby wystarczyło tylko prywatne dziedziczenie wirtualne." "Nikt tutaj nie twierdził, że idiom pieczęci działa bez prywatnego ctor. W idiomie uszczelniającym prywatne dziedziczenie nie jest potrzebne, ale jest potrzebne, aby użycie idiomu było szczegółem implementacji. – curiousguy