Inherit and overload default constructor - c++

I've been searching for this and I'm amazed I haven't found anything. Why can't I inherit a base class constructor using using declaration and add an overload in the derived class? I'm using Visual C++ 2013, the base class constructor is ignored when default-constructing b:
error C2512: 'B' : no appropriate default constructor available
I've dealt with this by re-defining the constructors, but I don't like that. This is just a minimal example, it wouldn't bother me if I had only one base class constructor.
struct A
{
A() : a(10) {}
int a;
};
struct B : A
{
using A::A;
explicit B(int a) { this->a = a; }
};
int main()
{
B b;
}

The problem is that default-constructors are not inherited. From [class.inhctor]/p3:
For each non-template constructor in the candidate set of inherited constructors [..], 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.
You also have a user-declared constructor that suppresses the creation of an implicit default-constructor. Just add a defaulted one to make it work:
B() = default;

Related

C++ Default constructor not inherited with "using" when move and copy constructors present

class A{
public:
A(){};
};
class B : public A{
public:
using A::A;
B(const B&) = default;
B( B&&) = default;
};
B b;
The compiler (g++ (5.4.0-6ubuntu1) / c++11) says "no matching function for call to B::B()" and lists the copy and move constructors as candidates. If I comment those defaulted ones out then it compiles. What causes this? And what difference does it make that they are explicitly defaulted? If those 2 lines weren't there they would be defaulted anyway.
Before C++17, the default constructor of the base class won't be inherited via using:
All candidate inherited constructors that aren't the default constructor or the copy/move constructor and whose signatures do not match user-defined constructors in the derived class, are implicitly declared in the derived class. (until C++17)
After C++17 the code works fine.
Before that, the default constructor won't be inherited from the base class, and won't be generated for class B because copy/move constructor are provided.
If no user-declared constructors of any kind are provided for a class type (struct, class, or union), the compiler will always declare a default constructor as an inline public member of its class.
That's why if you comment copy/move constructor out it compiles. You can add the definition explicitly as a pre-C++17 workaround. e.g.
class B : public A {
public:
B(const B&) = default;
B( B&&) = default;
B() = default;
};
The code compiles with gcc8.
If you declare any constructors, the default constructor is not implicitly generated, you can generate it by adding a = default for it as well:
class B : public A {
public:
B() = default;
B(const B&) = default;
B( B&&) = default;
};
This has changed with C++17 (as pointed out by other answer).
The default constructor cannot be inherited, the standard explicitly says so. Quoting C++11 12.9 [class.inhctor]/3 (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 class where the using-declaration appears. ...
This means that for the default constructor, normal rules apply as if the using A::A; declaration wasn't there. So the presence of any other constructor declaration (such as the copy & move constructor) causes the default constructor not to be implicitly declared. Note that you can easily add it back by explicitly defaulting it:
class B : public A{
public:
using A::A;
B() = default;
B(const B&) = default;
B( B&&) = default;
};
(*) The same wording is present in C++14 (n4140), at the same location. I can't seem to find equivalent wording in C++1z (looking through n4582)

Constructor of the base is not made available by the using declaration [duplicate]

I've been searching for this and I'm amazed I haven't found anything. Why can't I inherit a base class constructor using using declaration and add an overload in the derived class? I'm using Visual C++ 2013, the base class constructor is ignored when default-constructing b:
error C2512: 'B' : no appropriate default constructor available
I've dealt with this by re-defining the constructors, but I don't like that. This is just a minimal example, it wouldn't bother me if I had only one base class constructor.
struct A
{
A() : a(10) {}
int a;
};
struct B : A
{
using A::A;
explicit B(int a) { this->a = a; }
};
int main()
{
B b;
}
The problem is that default-constructors are not inherited. From [class.inhctor]/p3:
For each non-template constructor in the candidate set of inherited constructors [..], 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.
You also have a user-declared constructor that suppresses the creation of an implicit default-constructor. Just add a defaulted one to make it work:
B() = default;

C++, inherited copy ctors does not work?

Consider following code:
class TBase {
public:
TBase();
TBase(const TBase &);
};
class TDerived: public TBase {
public:
using TBase::TBase;
};
void f() {
TBase Base;
TDerived Derived(Base); // <=== ERROR
}
so, I have base and derived classes, and want to use "using TBase::TBase" to pull copy ctor from base class to be able to create instance of derived class in such way:
TDerived Derived(Base);
But all compilers rejects this with these error messages
7 : note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'TBase' to 'const TDerived' for 1st argument
Why? What am I doing wrong? Why "using TBase::TBase" does not work in this situation?
UPDATE
How can be explained following piece of code from cppreference.com?
struct B1 {
B1(int);
};
struct D1 : B1 {
using B1::B1;
// The set of inherited constructors is
// 1. B1(const B1&)
// 2. B1(B1&&)
// 3. B1(int)
Copy and move consturctors (and the default constructor) are never inherited, simply because the standard says so. All other constructors are.
That comment on cppreference was misleading(1). The same comment in the standard says:
The candidate set of inherited constructors in D1 for B1 is
(Emphasis mine).
The standard then goes on to say that only the D1(int) constructor is actually inherited. The copy and move constructors for D1 are implicitly-declared as for any other class, not inherited.
Refer to C++14 12.9 [class.inhctor] for details.
(1) I submitted a change to cppreference to hopefully clarify this.
If you further read the same piece of code, it says:
// D1 has the following constructors:
// 1. D1()
// 2. D1(const D1&)
// 3. D1(D1&&)
// 4. D1(int) <- inherited
};
Thus a copy ctor is still the copy ctor, it accepts an argument of class TDerived. D1(int) is generated automatically nevertheless.
As per standard 12.6.3/p1 Initialization by inherited constructor [class.inhctor.init] (Emphasis Mine):
When a constructor for type B is invoked to initialize an object of a
different type D (that is, when the constructor was inherited
(7.3.3)), initialization proceeds as if a defaulted default
constructor were used to initialize the D object and each base class
subobject from which the constructor was inherited, except that the B
subobject is initialized by the invocation of the inherited
constructor. The complete initialization is considered to be a single
function call; in particular, the initialization of the inherited
constructor’s parameters is sequenced before the initialization of any
part of the D object.
Thus, constructors are not actually inherited but rather they're implicitly or explicitly called by the respective derived constructor. Also keep in mind that the inherited constructors are simply calling the base constructors and do not perform any member initialization in the derived object.
To clarify this consider the following example:
struct Base {
Base(int);
...
};
struct Derived : Base {
using Base::Base;
...
};
The above Derived class definition is syntactically equivalent with:
struct Derived : Base {
Derived(int i) : Base(i) {}
...
};
That is, the using declaration in the Derived class implicitly defines the constructor Derived(int). At this point mind also that if the constructor is inherited from multiple base class sub-objects Derived, the program is ill-formed.
In the same manner you've been lead to the logical conclusion that since I've declared in the base class a copy constructor with the using declaration:
class TBase {
public:
TBase();
TBase(const TBase &);
};
class TDerived: public TBase {
public:
using TBase::TBase;
};
I would get the following syntactical equivalent Derived class:
class TDerived: public TBase {
public:
TDerived() : Base() {}
TDerived(TBase const &other) : Base(other) {}
};
However, this is not the case. You can't "inherit" a copy constructor neither a default constructor neither a move constructor. Why? because this is how the C++ standard dictates so.
What you can do instead is to define a user defined constructor that will take as input a base class object:
class TDerived: public TBase {
public:
TDerived(TBase const &other) {}
};
After all TDerived and TBase are different classes even though the first inherits the second one.

Constructor with default arguments can not be called when inherited [duplicate]

I've been searching for this and I'm amazed I haven't found anything. Why can't I inherit a base class constructor using using declaration and add an overload in the derived class? I'm using Visual C++ 2013, the base class constructor is ignored when default-constructing b:
error C2512: 'B' : no appropriate default constructor available
I've dealt with this by re-defining the constructors, but I don't like that. This is just a minimal example, it wouldn't bother me if I had only one base class constructor.
struct A
{
A() : a(10) {}
int a;
};
struct B : A
{
using A::A;
explicit B(int a) { this->a = a; }
};
int main()
{
B b;
}
The problem is that default-constructors are not inherited. From [class.inhctor]/p3:
For each non-template constructor in the candidate set of inherited constructors [..], 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.
You also have a user-declared constructor that suppresses the creation of an implicit default-constructor. Just add a defaulted one to make it work:
B() = default;

Value initialization

$8.5/7 states that
— if T is a (possibly cv-qualified) non-union class type without a user-provided constructor, then the object
is zero-initialized and, if T’s implicitly-declared default constructor is non-trivial, that constructor is
called.
I am unable to appreciate the last part of this statement "if T’s implicitly-declared default constructor is non-trivial, that constructor is called."
Can someone please explain this with an example?
class A
{
int x;
};
class B : A {};
B b{};
I think B in the code above is having a non-trivial constructor. But how do I observe call to B's implicitly declared constructor and make sure that my compiler is calling it?
I think B in the code above is having a non-trivial constructor.
In your example, the constructor is trivial.
Looking at the conditions in C++11 12.1/5, neither class has a user-declared constructor, virtual functions, virtual base classes, members with initialisers, or members of class type; A has no base classes and B only has a trivial base class.
But how do I observe call to B's implicitly declared constructor and make sure that my compiler is calling it?
One way to make a class with an implicit, but non-trivial, default constructor is to have a non-trivial member or base class:
struct A {
// A user-declared constructor is non-trivial
A() {std::cout << "Construct A\n";}
};
struct B : A {};
Now you can (indirectly) observe the implicit constructor of B being called, by observing the side-effect when it calls the constructor of A.
Explanation after N3797:
A function is user-provided if it is user-declared and not explicitly
defaulted or deleted on its first declaration.
Therefore, since you don't declare a default constructor for B, it is not user-provided.
The following then applies:
A default constructor is trivial if it is not user-provided and if:
— its class has no virtual functions (10.3) and no virtual base
classes (10.1), and
— no non-static data member of its class has a
brace-or-equal-initializer, and
— all the direct base classes of its class have trivial default
constructors, and
— for all the non-static data members of its class that are of class
type (or array thereof), each such class has a trivial default
constructor.
So it is indeed trivial, since we can apply the same procedure recursively for A.
Other examples:
struct A { A() = default; }; // Trivial default constructor!
struct A { A() = delete; }; // Also trivial!
struct A { A(); }; // Can't be trivial!
struct B { virtual void f(); }
struct A : B {}; // Non-trivial default constructor.
struct B {};
struct A : virtual B {}; // Non-trivial default constructor.
Imagine you have this one
struct A {
string a;
int value;
};
int main() {
A a = A();
return a.value;
}
a.value is zero when we return that value, because the object was zero-initialized. But that is not enough, because a also contains a string member which has a constructor. For that constructor to be called, the standard arranges that A's constructor is called, which will eventually lead to constructing the member.