Конструктор копирования не наследуется

У меня есть следующий код:

class C {
public:
    C(int) {}
    C(const C&) {}
    C() {}
};  

class D : public C { 
public:
    using C::C;
};  

int main() {
    C c;
    D d_from_c(c); // does not compile, copy ctor is not inherited
    D d_from_int(1); // compiles, C(int) is inherited
}   

Производный класс должен наследовать все ctors базы, кроме значения по умолчанию ctor (объясняется здесь). Но зачем копировать ctor тоже не унаследовано? Аргументы из связанного с этим вопроса здесь неприемлемы.

Код компилируется с помощью g++ 4.8.1.

Ответ 1

Потому что стандарт говорит так. [class.inhctor]/p3, основное внимание:

Для каждого конструктора без шаблона в наборе кандидатов унаследованных конструкторы , кроме конструктора, не имеющего параметров или copy/move, имеющий единственный параметр, конструктор неявно объявляется с теми же характеристиками конструктора, если только есть конструктор с объявленным пользователем с той же сигнатурой в полный класс, где появляется декларация использования или конструктор будет конструктором по умолчанию, копией или перемещением для этого класса.

Ответ 2

Производный класс должен наследовать все ctors базы, за исключением значения по умолчанию ctor

Нет, это не так, см. T.C. answer для реального правила.

Цель наследования конструкторов - сказать, что "производный тип может быть создан из тех же аргументов, что и базовый тип", но это не относится к конструктору копии базового класса, поскольку конструктор копирования - это не просто способ сказать, как создать тип из заданного аргумента.

Конструктор копирования является специальным, он предназначен для копирования объекта того же типа.

Конструктор D(const C&) не использовался бы для копирования объекта того же типа, потому что C не является тем же типом, что и D.

Ответ 3

На какое-то время предположим, что допустимо наследование конструктора экземпляров. Если ваша структура классов не повреждена, рассмотрите следующий код для модифицированного основного метода.

int main() {
    C c;
    D d;
    D d_from_d(d);
    D d_from_c(c); // does not compile, copy ctor is not inherited
    D d_from_int(1); // compiles, C(int) is inherited
}  

В D d_from_d(d), как обычный вызов конструктора, будут два вызова конструктора копий. Один для C:: C (const C &), а другой - для созданного компилятором конструктора копии для D. Имея тип исходного объекта в D (d в этом случае), конструктор Cs copy может копировать атрибуты ds C при генерировании компилятора Ds copy конструктор может копировать атрибут ds D.

Но в случае D d_from_c(c) Нет проблемы для конструктора Cs copy, потому что атрибуты cs C могут быть экземплярами с помощью конструктора Cs copy. Но как создатель компилятора, созданный конструктором Ds, знает способ копирования атрибутов Ds из объекта Cs. Это конфликт, которого следует избегать.

Но если вы предоставили какой-то "странный конструктор копирования" (возможно, вам понадобится также конструктор по умолчанию), например:

D(const C & c):C(c){} 

Тогда,  вызов D d_from_c(c); действует. Потому что теперь мы явно предоставили соответствующий "конструктор копирования".

Таким образом, использование разрешений "Унаследованные копии" недействительно.