Caveat with C++11 inherited constructor - c++

https://en.wikipedia.org/wiki/C++11#Object_construction_improvement
For base-class constructors, C++11 allows a class to specify that base
class constructors will be inherited. Thus, the C++11 compiler will
generate code to perform the inheritance and the forwarding of the
derived class to the base class. This is an all-or-nothing feature:
either all of that base class's constructors are forwarded or none of
them are. Also, restrictions exist for multiple inheritance, such that
class constructors cannot be inherited from two classes that use
constructors with the same signature. Nor can a constructor in the
derived class exist that matches a signature in the inherited base
class.
Can someone give me an example to illustrate the issue with "Nor can a constructor in the derived class exist that matches a signature in the inherited base class."?

It means that if you have constructor in the derived class whose parameter list matches the parameter list of any constructor in the base class, then that derived class' constructor is taken and hides the base class'
E.g.
struct Foo
{
Foo(){std::cout << "Foo default ctor\n";}
Foo(int){std::cout << "Foo(int)\n";}
};
struct Bar : Foo
{
using Foo::Foo;
Bar(int){std::cout << "Bar\n";} // won't implicitly call Foo(int)
};
int main()
{
Bar b(1);
}
From §12.9/3 [class.inhctor] (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.

Related

Why base class copy and move constructors should not be inherited?

CWG2356:
Base class copy and move constructors brought into a derived class via a using-declaration should not be considered by overload resolution when constructing a derived class object.
But other constructors that are inherited from the base class only initializes the base class subobject, too.
So, why base class copy and move constructors should not be inherited?
Keep in mind, the default implementations of the copy/move constructors of the derived class already call the base class copy/move constructors. If the base class copy and move constructors were eligible for overload resolution, you would make the following legal, which in general is not desirable:
Base b;
Derived d = b;

inheriting default constructor, a contradiction?

In C++ (inheritance subject) I read:
A derived class automatically has a default constructor, a copy
constructor, and an assignment operator, like any other class. The
compiler-generated default constructor calls the base class default
constructor
But on the other hand:
The base class constructors are not inherited We must explicitly
define any constructors the derived class needs
1) what does it mean to inherit a constructor?
2) isn't what is written above a contradiction?
I hope to add some examples if possible to help me understand.
"The base class constructors are not inherited" means that any constructor defined in a class Base is not available for a derived class Derived unless it is re-defined in Derived. This is also valid for the default constructor. But, "A derived class automatically has a default constructor" says that the compiler will automatically generate a default constructor, just as it does for every class. So the compiler will re-define a default constructor in a derived class; it is still not inherited.
The only thing is that "We must explicitly define any constructors the derived class needs", if there is no context under which this statement shall hold, seems wrong. There are definitely constructors available in a derived class that have not been defined explicitely. This can be shown easily by defining a derived class without any explicit constructor:
struct Base {
Base () { std::cout << "in default constructor of Base; not inherited, but still called." << std::endl; };
};
struct Derived : public Base {
// no explicitly defined constructor...
};
int main() {
Derived d;
}
Output:
in default constructor of Base; not inherited, but still called.
So I'd tend to say that the statement "... We must explicitly define any constructors the derived class needs" you cited is either not precise, not shown in full context, or wrong.
struct s {
s() : s_str("my string") {}; // default constructor
std::string s_str;
};
struct d : s {
std::string d_str;
};
If d didn't have any members that needed construction, the default constructor would simply construct s with s::s() which superficially looks like inheritance (and could be implemented that way). But when you add data members to the derived class, that won't work.
The default constructor for s constructs s_str with the text "my string".
If s::s() was inherited in d it wouldn't know about d_str, so wouldn't construct it. So it's not inherited.
Instead, the compiler generates a default constructor for d that constructs d_str with the default constructor for std::string and constructs the s base with s::s().

Move constructor disappears in derived class when adding custom destructor

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.

using Base::Base; in Derived class, what does that do exactly? [duplicate]

In C++11, what is meant by inheriting the constructor? If it is what i think it is (Base class constructor is brought in the scope of the derived class), what are its implications on my code? What are the applications of such a feature?
Inheriting Constructors means just that. A derived class can implicitly inherit constructors from its base class(es).
The syntax is as follows:
struct B
{
B(int); // normal constructor 1
B(string); // normal constructor 2
};
struct D : B
{
using B::B; // inherit constructors from B
};
So now D has the following constructors implicitly defined:
D::D(int); // inherited
D::D(string); // inherited
Ds members are default constructed by these inherited constructors.
It is as though the constructors were defined as follows:
D::D(int x) : B(x) {}
D::D(string s) : B(s) {}
The feature isn't anything special. It is just a shorthand to save typing boilerplate code.
Here are the gory details:
12.9 Inheriting Constructors
1) A using-declaration that names a constructor implicitly declares a
set of inheriting constructors. The candidate set of inherited
constructors from the class X named in the using-declaration consists
of actual constructors and notional constructors that result from the
transformation of defaulted parameters as follows:
all non-template constructors of X, and
for each non-template constructor of X that has at least one parameter with a default argument, the set of constructors that
results from omitting any ellipsis parameter specification and
successively omitting parameters with a default argument from the end
of the parameter-type-list, and
all constructor templates of X, and
for each constructor template of X that has at least one parameter with a default argument, the set of constructor templates that results
from omitting any ellipsis parameter specification and successively
omitting parameters with a default argument from the end of the
parameter-type-list

order of calling constructor in inheritance

I am new to C++ programming language, i have a confusion about order of calling the constructor in inheritance. my question is even though the constructor and destructor are not inherited by derived class why the base class constructor will call when i create a derived class object.
The purpose of a constructor is to define how the data members should be initialised. Since a derived class inherits the data members from the base class, any constructor of the derived class must define not only how to initialise the data members that are specific to the derived class, but also those coming from the base class.
The natural way to do this (and required by the C++ Standard) is by calling a base class constructor. If you don't include a specific constructor call in the initialization list for your derived-class constructor, the default constructor of the base class will be used to initialise the base-class members.
struct base
{
int _i; // a data member
base():_i(0) {} // default constructor
base(int i):_i(i) {} // special constructor
};
struct derived : base
{
int _j; // a data member specific to the derived class
derived(int i, int j):_j(j) {} // user-defined constructor for the derived class
};
The example above illustrates how the derived-class constructor can initialise its member _j, but the member _i, coming from the base class, must be initialised using a base-class constructor.
The way it's written above, the default constructor base::base() will be automatically called by the compiler, i.e. _i will be initialised to 0.
But you can change that behaviour by including a call to a specific constructor:
struct derived : base
{
int _j;
derived(int i, int j):base(i),_j(j) {} // user-defined constructor for the derived class
};
The order of the constructor calls is: First constructor calls of the base class, then initializers for the derived-class specific members. This is only natural because the derived class, in a sense, is an extension of the base class, and it makes sense to regard the base-class part of the derived-class object as being there first.