I'm trying to inherit constructors from the base class and define an additional constructor in the derived class.
#include <iostream>
#define BREAK_THIS_CODE 1
class Base
{
public:
Base()
{
std::cout << "Base " << "\n";
}
Base(int i)
{
std::cout << "Base " << i << "\n";
}
};
class Derived : public Base
{
public:
using Base::Base;
#if BREAK_THIS_CODE
Derived(int i, int j)
{
std::cout << "Derived " << i << " " << j << "\n";
}
#endif
};
int main()
{
Derived d1(10);
Derived d2; // error C2512: 'Derived': no appropriate default constructor available
return 0;
}
Adding Derived(int, int) seems to delete Base() but Base(int) is unaffected by this. Why is the default constructor getting removed? I expected Derived to have a total of three user-defined constructors. The only thing I can think of is the inherited Base() constructor is being treated as an implicitly-declared default constructor and adding an extra constructor is deleting the default constructor.
I've tried this on VS2015 and get the following error:
1> main.cpp
1>main.cpp(37): error C2512: 'Derived': no appropriate default constructor available
1> main.cpp(19): note: see declaration of 'Derived'
Also tried this example on Coliru: http://coliru.stacked-crooked.com/a/790b540c44dccb9f
clang++ -std=c++11 -O3 -pedantic -pthread main.cpp && ./a.out
main.cpp:35:10: error: no matching constructor for initialization of 'Derived'
Derived d2;
^
main.cpp:22:14: note: candidate constructor (inherited) not viable: requires 1 argument, but 0 were provided
using Base::Base;
^
main.cpp:13:2: note: inherited from here
Base(int i)
^
main.cpp:19:7: note: candidate constructor (the implicit copy constructor) not viable: requires 1 argument, but 0 were provided
class Derived : public Base
^
main.cpp:19:7: note: candidate constructor (the implicit move constructor) not viable: requires 1 argument, but 0 were provided
main.cpp:25:2: note: candidate constructor not viable: requires 2 arguments, but 0 were provided
Derived(int i, int j)
^
1 error generated.
Per CppReference:
If the using-declaration refers to a constructor of a direct base of the class being defined (e.g. using Base::Base;), constructors of that base class are inherited, according to the following rules:
1) A set of candidate inheriting constructors is composed of
[rules here]
2) 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. The default parameters are not inherited
So you cannot inherit a default constructor. When a class has declared a user-defined constructor, the compiler does not generate a default constructor for that class, unless you explicitly ask for one using Derived() = default. When you remove your user-defined constructor, the compiler can then generate a default constructor for you.
Related
#include <iostream>
using namespace std;
class Test{
private:
Test(int a, int b=0)
{
cout << "private constructor\n";
}
public:
Test(int a)
{
cout << "public constructor\n";
}
};
int main()
{
Test t(1);
}
When I attempted to compile the code gcc says:
test.cpp: In function ‘int main()’:
test.cpp:20:10: error: call of overloaded ‘Test(int)’ is ambiguous
Test t(1);
^
test.cpp:12:2: note: candidate: Test::Test(int)
Test(int a)
^
test.cpp:7:2: note: candidate: Test::Test(int, int)
Test(int a, int b=0)
^
test.cpp:5:7: note: candidate: Test::Test(const Test&)
class Test{
^
and clang says:
test.cpp:20:7: error: call to constructor of 'Test' is ambiguous
Test t(1);
^ ~
test.cpp:7:2: note: candidate constructor
Test(int a, int b=0)
^
test.cpp:12:2: note: candidate constructor
Test(int a)
^
test.cpp:5:7: note: candidate is the implicit copy constructor
class Test{
^
1 error generated.
What is the reason of the ambiguity? Since Test(int,int) is private, it shouldn't be possible to call it in Test t(1). A possible answer is (what I thought initially), it makes two identical signatures of constructors possible, i.e Test() can be called with only one int in private constructor. But in the program code Test t(1) is only feasible for public constructors, so it shouldn't offer the private constructor as a candidate. Why does it say that?
It's ambiguous for an explicit reason, as according to the standard:
[class.access/5]
It should be noted that it is access to members and base classes that
is controlled, not their visibility. Names of members are still
visible, and implicit conversions to base classes are still
considered, when those members and base classes are inaccessible. The
interpretation of a given construct is established without regard to
access control. If the interpretation established makes use of
inaccessible member names or base classes, the construct is
ill-formed.
And that visibility means that the compiler must consider both overloads for the construction, and they are equally good for the argument you passed.
Since the constructor is private, and therefore only accessible withing the scope of the class and its members, just remove the default parameter value. You can maintain this default value in your classes definition in other ways. For instance, by introducing a constant in the classes implementation file:
int const default_b = 0;
// ...
return Test{a, default_b};
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;
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;
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;
In this piece of code, why is A's constructor with no parameters not inherited? Is there a special rule that prevents inheriting constructors with no parameters?
struct A {
A(void *) {}
A() {}
};
class B : public A {
public:
using A::A;
B(int x) {}
};
void f() {
B b(1);
B b2(nullptr);
B b3; // error
}
clang++ -std=c++11 gives this error, and g++ -std=c++11 gives a substantially similar error message:
td.cpp:15:7: error: no matching constructor for initialization of 'B'
B b3; // error
^
td.cpp:9:5: note: candidate constructor not viable: requires single argument 'x', but no arguments
were provided
B(int x) {}
^
td.cpp:8:14: note: candidate constructor (inherited) not viable: requires 1 argument, but 0 were
provided
using A::A;
^
td.cpp:2:5: note: inherited from here
A(void *) {}
The relevant information is in 12.9 [class.inhctor] paragraph 3 (the highlighting is added):
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. [...]
That is, default constructor are not inherited unless they have a [defaulted] argument. If they have a default argument they are inherited but without the defaulted argument as is pointed out by a node on the same paragraph:
Note: Default arguments are not inherited. [...]
Basically, that says that default constructors are not inherited.
there is no constructor in B with no parameters, try
B() : A(){}