I've got the following code:
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
}
Derived class should inherit all ctors of base except the default ctor (it is explained here). But why copy ctor is not inherited as well? Arguments from the related question are not acceptable here.
The code is compiled with g++ 4.8.1.
Because the standard says so. [class.inhctor]/p3, emphasis mine:
For each non-template constructor in the candidate set of inherited
constructors other than a constructor having no parameters or a
copy/move constructor having a single parameter, a constructor is
implicitly declared with the same constructor characteristics unless
there is a user-declared constructor with the same signature in the
complete class where the using-declaration appears or the constructor
would be a default, copy, or move constructor for that class.
Derived class should inherit all ctors of base except the default ctor
No, that's not true, see T.C.'s answer for the real rule.
The purpose of inheriting constructors is to say "the derived type can be created from the same arguments as the base type", but that isn't relevant for the base class' copy constructor, because a copy constructor is not just a way of saying how to create a type from a given argument.
A copy constructor is special, it's for copying an object of the same type.
A constructor D(const C&) would not used be for copying an object of the same type, because C is not the same type as D.
For a moment, we’ll assume ‘copy constructor inheritance’ is allowed.
Having your class structure intact, please consider following code for modified main method.
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
}
In D d_from_d(d), as a normal constructor call, there will be two copy constructor calls. One for C::C(const C&) and the other one is for compiler generated copy constructor for D. Having source object type in D (d in this case), C’s copy constructor can copy d’s C attributes while compiler generated D’s copy constructor can copy d’s D attribute.
But in D d_from_c(c) case, There is no problem for C’s copy constructor because, c’s C attributes can be copies by C’s copy constructor. But how does the compiler generated D’s copy constructor know the way to copy ‘D’s attributes from C’s object’. This is a conflict which should be avoided.
But, if you provide some sort of ‘weird copy constructor’ (you may need to a default constructor as well) like;
D(const C & c):C(c){}
Then,
calling D d_from_c(c);
is valid. Because, now we have explicitly provided a matching ‘copy’ constructor.
So, saying ‘Inheriting copy constructors are now allowed’ is invalid.
Related
I've got the following code:
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
}
Derived class should inherit all ctors of base except the default ctor (it is explained here). But why copy ctor is not inherited as well? Arguments from the related question are not acceptable here.
The code is compiled with g++ 4.8.1.
Because the standard says so. [class.inhctor]/p3, emphasis mine:
For each non-template constructor in the candidate set of inherited
constructors other than a constructor having no parameters or a
copy/move constructor having a single parameter, a constructor is
implicitly declared with the same constructor characteristics unless
there is a user-declared constructor with the same signature in the
complete class where the using-declaration appears or the constructor
would be a default, copy, or move constructor for that class.
Derived class should inherit all ctors of base except the default ctor
No, that's not true, see T.C.'s answer for the real rule.
The purpose of inheriting constructors is to say "the derived type can be created from the same arguments as the base type", but that isn't relevant for the base class' copy constructor, because a copy constructor is not just a way of saying how to create a type from a given argument.
A copy constructor is special, it's for copying an object of the same type.
A constructor D(const C&) would not used be for copying an object of the same type, because C is not the same type as D.
For a moment, we’ll assume ‘copy constructor inheritance’ is allowed.
Having your class structure intact, please consider following code for modified main method.
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
}
In D d_from_d(d), as a normal constructor call, there will be two copy constructor calls. One for C::C(const C&) and the other one is for compiler generated copy constructor for D. Having source object type in D (d in this case), C’s copy constructor can copy d’s C attributes while compiler generated D’s copy constructor can copy d’s D attribute.
But in D d_from_c(c) case, There is no problem for C’s copy constructor because, c’s C attributes can be copies by C’s copy constructor. But how does the compiler generated D’s copy constructor know the way to copy ‘D’s attributes from C’s object’. This is a conflict which should be avoided.
But, if you provide some sort of ‘weird copy constructor’ (you may need to a default constructor as well) like;
D(const C & c):C(c){}
Then,
calling D d_from_c(c);
is valid. Because, now we have explicitly provided a matching ‘copy’ constructor.
So, saying ‘Inheriting copy constructors are now allowed’ is invalid.
I have a move-only Base class and a Derived which inherits Base's constructors. I would like to give a Derived a custom destructor, but when I do so it no longer inherits Base's move constructor. Very mysterious. What is happening?
godbolt
// move-only
struct Base {
Base() = default;
Base(Base const &) = delete;
Base(Base &&) {}
};
struct Derived : public Base {
using Base::Base;
// remove this and it all works
~Derived() { /* ... */ }
};
int main() {
Base b;
// works
Base b2 = std::move(b);
Derived d;
// fails
Derived d2 = std::move(d);
}
The move constructor is not inherited with using Base::Base; in the way that you seem to think it is, because the move constructor in Base does not have the signature that a move constructor in Derived would have. The former takes a Base&&, the latter a Derived&&.
Then in Derived you are declaring a destructor. This inhibits the implicit declaration of a move constructor for Derived. So there is no move constructor in Derived.
The compiler then falls back to Derived's implicitly generated copy constructor for Derived d2 = std::move(d);. But that is defined as deleted because the base class of Derived is not copy-able. (You manually deleted Bases copy constructor.)
In overload resolution the deleted copy constructor is chosen over the Base classes inherited Base(Base&&) constructor (although a Derived rvalue could bind to Base&&), because the latter requires a conversion sequence that is not considered exact match, while binding to a const Derived& is considered exact match for the purpose of overload resolution.
Also there is the proposed wording for the resolution of CWG issue 2356 which would exclude the inherited Base move constructor from participating in overload resolution at all. (From what I can tell this is what the compiler are implementing already.)
If you don't have a good reason to declare a destructor, don't do so. If you do have a reason, then you need to default the move operations again, as you did for the move constructor in Base. (You probably want to default the move assignment operator as well if the classes are supposed to be assignable.)
If you intend to use the class hierarchy polymorphically, you should declare a virtual (defaulted) destructor in the polymorphic base, but you do not need to declare a destructor in the derived classes.
Move constructors are generated under specific circumstances.
https://en.wikipedia.org/wiki/Special_member_functions
In creating a destructor, you have stopped the generation of a move constructor by the compiler.
Also, create a virtual Base destructor if you don't have one. Default it if it doesn't have to do anything special. Same with your Base move constructor, just don't leave it empty, declare it default. You're using =delete, use =default as well.
The inherited move constructor does not have the signature for the derived class.
In the first case without the explicitly declared destructor the compiler implicitly declares the default move constructor for the derived class.
In the second case when the destructor is explicitly declared the move constructor is not implicitly declared by the compiler.
From the C++ 17 Standard (15.8.1 Copy/move constructors)
8 If the definition of a class X does not explicitly declare a move
constructor, a non-explicit one will be implicitly declared as
defaulted if and only if
(8.1) X does not have a user-declared copy constructor,
(8.2) X does not have a user-declared copy assignment operator,
—(8.3) X does not have a user-declared move assignment operator, and
> —(8.4) X does not have a user-declared destructor.
But in any case the ,move constructor of the base class is not the move constructor of the derived class due to different signatures.
I've got the following code:
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
}
Derived class should inherit all ctors of base except the default ctor (it is explained here). But why copy ctor is not inherited as well? Arguments from the related question are not acceptable here.
The code is compiled with g++ 4.8.1.
Because the standard says so. [class.inhctor]/p3, emphasis mine:
For each non-template constructor in the candidate set of inherited
constructors other than a constructor having no parameters or a
copy/move constructor having a single parameter, a constructor is
implicitly declared with the same constructor characteristics unless
there is a user-declared constructor with the same signature in the
complete class where the using-declaration appears or the constructor
would be a default, copy, or move constructor for that class.
Derived class should inherit all ctors of base except the default ctor
No, that's not true, see T.C.'s answer for the real rule.
The purpose of inheriting constructors is to say "the derived type can be created from the same arguments as the base type", but that isn't relevant for the base class' copy constructor, because a copy constructor is not just a way of saying how to create a type from a given argument.
A copy constructor is special, it's for copying an object of the same type.
A constructor D(const C&) would not used be for copying an object of the same type, because C is not the same type as D.
For a moment, we’ll assume ‘copy constructor inheritance’ is allowed.
Having your class structure intact, please consider following code for modified main method.
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
}
In D d_from_d(d), as a normal constructor call, there will be two copy constructor calls. One for C::C(const C&) and the other one is for compiler generated copy constructor for D. Having source object type in D (d in this case), C’s copy constructor can copy d’s C attributes while compiler generated D’s copy constructor can copy d’s D attribute.
But in D d_from_c(c) case, There is no problem for C’s copy constructor because, c’s C attributes can be copies by C’s copy constructor. But how does the compiler generated D’s copy constructor know the way to copy ‘D’s attributes from C’s object’. This is a conflict which should be avoided.
But, if you provide some sort of ‘weird copy constructor’ (you may need to a default constructor as well) like;
D(const C & c):C(c){}
Then,
calling D d_from_c(c);
is valid. Because, now we have explicitly provided a matching ‘copy’ constructor.
So, saying ‘Inheriting copy constructors are now allowed’ is invalid.
So I was wondering lately what the copy constructor of an class will look if we have a base class A that is being virtually inherited by B and C, where B and C are inherited by D and D is inherited by E.
So I am a bit confused. Should D's copy constructor still have the base class's (A) constructor in its initializing list or is that the job of E now? Am I correct that E could inherit D non-virtually?
The implicitly generated copy constructor works fine, but if you wanted to explicitly write it yourself it could look like:
D(D const &o): A(o), B(o), C(o) {}
E(E const &o): A(o), D(o) {}
For initialization purposes, virtual base classes behave as if they are a direct base of the most-derived object. Any initializer in a subobject is ignored (e.g. in my code for E, the initialization D(o) actually does not initialize the A despite the fact that A is listed in D's copy constructor).
This is the same whether or not E inherits D virtually.
Link to further reading
Yes, A should still be in the initializing list and E does not need to inherit D virtually. The order of construction should be:
A() --> B() --> C() --> D()
I know this kind of question has been asked many times, and I've read different answers about it, as well as some parts of the ISO standard.
But still, I need a few clarifications about the exact behaviour expected by the C++ standard.
Assuming this:
class A
{
public:
A( void ) {}
A( const A & a ) {}
};
class B: public A
{
public:
B( void ) {}
B( const B & b ) {}
};
I know that calling the copy constructor of the B class won't call the copy constructor of the A class, and that we can use an initialisation list in order to do it properly.
I also know about using using in order to inherit constructors.
But what does the standard exactly mandates about a derived class which does not provides explicitly a copy constructor, while the base class does:
class A
{
public:
A( void ) {}
A( const A & a ) {}
};
class B: public A
{};
I always thought the compiler would implicitly define a copy constructor for class B, thus hiding the copy constructor of class A, which won't be called.
However, looks like it's not the case, and the the A copy constructor is called.
Compiling with Clang on OS X 10.10.
So is this something mandatory, or something that can be implementation defined, meaning we should not rely on this behaviour?
In the C++ standard, I've found the following, but it's clearly not crystal-clear to me:
An inheriting constructor for a class is implicitly defined when it is
odr-used (3.2) to create an object of its class type (1.8). An
implicitly-defined inheriting constructor performs the set of
initializations of the class that would be performed by a user-written
inline constructor for that class with a mem-initializer-list whose
only mem-initializer has a mem-initializer-id that names the base
class denoted in the nested-name-specifier of the using-declaration
and an expression-list as specified below, and where the
compound-statement in its function body is empty (12.6.2).
I would really enjoy a clarification on it, in accordance with the standard, and also with multiple inheritance in mind.
From http://en.cppreference.com/w/cpp/language/copy_constructor (emphasis mine):
Implicitly-defined copy constructor
If the implicitly-declared copy constructor is neither deleted nor
trivial, it is defined (that is, a function body is generated and
compiled) by the compiler if odr-used. For union types, the
implicitly-defined copy constructor copies the object representation
(as by std::memmove). For non-union class types (class and struct),
the constructor performs full member-wise copy of the object's bases
and non-static members, in their initialization order, using direct
initialization.
So it seems that compiler generated copy constructor will call the base copy constructor just as it calls the copy constructors of the members.