8

Jak stwierdził [namespace.udecl]/18:dziedziczone konstruktorzy, domyślny konstruktor i widoczność

[...] A z użyciem deklaracja, że ​​nazwy konstruktor nie tworzy synonim; zamiast tego dodatkowe konstruktory są dostępne, jeśli byłyby dostępne, gdy są używane do konstruowania obiektu odpowiedniej klasy bazowej, a dostępność deklaracji użycia jest ignorowana. [...]

Z tego powodu, poniższy kod nie kompilacji:

class B { protected: B(int) { } }; 
class D: B { using B::B; }; 
int main() { D d{0}; } 

Zwraca błąd, który jest mniej więcej taka sama w przypadku wszystkich głównych kompilatory:

uznanej chroniony tutaj

z drugiej strony, co następuje kod kompiluje:

class B { protected: B() { } }; 
class D: B { using B::B; }; 
int main() { D d{}; } 

Czy nie powinieneś go skompilować z tych samych powodów, które doprowadziły do ​​błędu w poprzednim przykładzie?
Co to pozwala na kompilację?

+2

Wskazówka: 'D' nie ma konstruktora deklarowanego przez użytkownika. –

+0

@ T.C. Myślałem o tym samym, ale "dostępność deklaracji użycia jest ignorowana", więc czy domyślny konstruktor nie powinien być dziedziczony i chroniony w drugim przypadku? – skypjack

+0

OK, kolejna wskazówka. Co dzieje się w wyrażeniu [class.ctor]/4, jeśli klasa nie ma konstruktora deklarowanego przez użytkownika? I jak to wchodzi w interakcję z konstruktorem klasy podstawowej, biorąc pod uwagę [namespace.udecl]/15? –

Odpowiedz

3

W drugim przypadku dziedziczący konstruktora nie jest uwzględniany. Zgodnie z regułami deleted implicitly-declared default constructor, że w 2. przypadku klasa D nie narusza (jest dobrze utworzony B::B() dla D); kompilator zadeklaruje domyślny konstruktor jako wbudowany element publiczny dla D, co powoduje, że D d{}; działa dobrze.

...

T ma bezpośredni lub wirtualną bazę, która ma usuniętą domyślnego konstruktora, lub jest niejednoznaczny lub niedostępne z tego konstruktora.

...

W 1. przypadku inheriting constructors trwa efekt:

(Kopalnia nacisk)

Jeśli rozdzielczość przeciążenie wybiera odziedziczony konstruktora, jest dostępny czy byłoby dostępne, gdy wykorzystane do skonstruowania obiekt odpowiedniej klasy bazowej: dostępność deklaracji użycia , która go wprowadziła jest ignorowana.

Jeśli rozpoznawanie przeciążenia wybiera jeden z dziedzicznymi konstruktorów gdy inicjalizacji przedmiot tej klasy pochodzą, a następnie podobiektu bazowa z którym konstruktor odziedziczyła jest inicjowany za pomocą odziedziczone konstruktora, a wszystkie inne zasady i członków Derywaty są zainicjowane tak, jakby były domyślnym konstruktorem domyślnym (domyślny element członkowski to inicjatory, jeśli zostały dostarczone, w przeciwnym razie nastąpi inicjalizacja domyślna ).

Następnie kończy się niepowodzeniem z powodu izolacji dostępu.

+0

Reguła dotycząca kopiowania/przenoszenia pochodzi z [tutaj] (http://eel.is/c++draft/namespace.udecl#4), ale skąd pochodzi reguła domyślna? – skypjack

+0

@skypjack Chodzi o to, że domyślny konstruktor zostanie wygenerowany dla klasy 'D' w drugim przypadku, co przyniesie efekt inny niż * dziedziczący konstruktor *. Odpowiedź została naprawiona. – songyuanyao

5
class B { protected: B() { } }; 
class D: B { using B::B; }; 
int main() { D d{}; } 

D ma konstruktora zdefiniowanego przez użytkownika nie w tym przypadku, więc kompilator generuje jedną (publiczne) dla ciebie, który wywołuje B::B (ale nie ze względu na using, że nie ma wpływu w tym przypadku), to kompilator Generator generowany jest następnie wywoływany przez main.

class B { protected: B(int) { } }; 
class D: B { using B::B; }; 
int main() { D d{0}; } 

Nawet D ma konstruktora zdefiniowanego przez użytkownika tutaj, jeden kompilator generowane jest niejawnie usunięty ponieważ B ma tylko konstruktora, który bierze int. D ma również konstruktora, który ma int (using), ale ten konstruktor jest oznaczony protected, a tym samym niedostępne przez main.

Powiązane problemy