No Matching Constructor For Initialization - c++

I'm just supposed to be getting used to basic copy constructors.
I assumed I properly placed copy constructors.
But when I try to compile, I keep getting the error "No matching constructor for initialization of B"
I'm a bit confused.
class A {
int valuea;
public:
A(const A&); // copy constructor
int getValuea() const { return valuea; }
void setValuea(int x) { valuea = x; }
};
class B : public A {
int valueb;
public:
B(int valueb);
B(const B&); // copy constructor
int getValueb() const { return valueb; }
void setValueb(int x) { valueb = x; }
};
int main () {
B b1;
b1.setValuea(5);
b1.setValueb(10);
B b2(b1);
cout << "b2.valuea=" << b2.getValuea() << "b2.valueb=" << b2.getValueb() << endl;
return 0;
}

By declaring B(int) and B(const B &), you have disabled the default constructor that is implicitly placed in the class for you when you have no other constructors because for all the compiler knows, you might not want a default constructor, so it can't make assumptions (see here).
Add the following to B, remembering to initialize the base and members with it:
B(){}
In C++11, this works well:
B() = default;
That will allow B to have a default constructor for use when you declare B b1;
The same thing goes for A, too. You have a copy constructor, so there's no longer any default constructor implicitly placed in for you.

Related

How do I set a default value for a class member with something other than its initializer list constructor

Let's say I have something like this:
class A
{
public:
A(int x, int y)
{
std::cout << "Constructed from parameters" << std::endl;
}
// Non-copyable, non-movable
A(A const&) = delete;
A(A&&) = delete;
A& operator=(A const&) = delete;
A& operator=(A&&) = delete;
};
class B
{
public:
B() = default;
private:
A a{1,2};
};
int main()
{
B b;
return 0;
}
This works fine, initializes a with a default value by calling A's constructor, and prints Constructed from parameters.
Then, let's say I want to initialize a differently, so I add a constructor that takes an initializer list and change my code:
class A
{
public:
A(int x, int y)
{
std::cout << "Constructed from parameters" << std::endl;
}
A(std::initializer_list<int> someList)
{
std::cout << "Constructed from an initializer list" << std::endl;
}
// Non-copyable, non-movable
A(A const&) = delete;
A(A&&) = delete;
A& operator=(A const&) = delete;
A& operator=(A&&) = delete;
};
class B
{
public:
B() = default;
private:
A a{1,2,3};
};
int main()
{
B b;
return 0;
}
Everything still works as I want, the code initializes a with a default value by calling A's second constructor and prints Constructed from an initializer list.
Now, let's say I want to keep A as is but go back to setting a's default value through the first constructor. If A was movable, I could use A a = A(1,2);, but that isn't the case here, so how do I go about this? Is it plain impossible to set a default value with that constructor?
Edit: I'm looking for a solution that would work with C++14, but if there is a better solution in C++17 or C++20 that's also something I want to know.
If A was movable, I could use A a = A(1,2);, but that isn't the case
here
Well, for C++17 and later, you can use A a = A(1,2); here, so long as you have that as the declaration/initialisation! The following works (in your second code snippet):
class B {
public:
B() = default;
private:
A a = A( 1, 2 ); // No assignment here - just an initialization.
};
and "Constructed from parameters" is called. This is because there is no actual assignment operation here, just an initialization. However, the following would fail, for the reason you have stated:
class B {
public:
B() { a = A( 1, 2 ); } // error C2280: 'A &A::operator =(A &&)': attempting to reference a deleted function
private:
A a{ 1,2,3 };
};
EDIT: Pre-C++17, the following is a workaround, using the 'old-fashioned' round parentheses, rather than curly braces, in an initializer list in the default constructor for B (tested with C++14 in clang-cl and MSVC):
class B {
public:
B() : a(1,2) {} // Using a{1,2} calls the "initializer list" constructor, however!
private:
A a;
};
I think this is not possible in C++14 without some kind of a "hack". One such hack is to employ an additional disambiguating parameter. For example:
class From_params {};
class A {
public:
A(int, int, From_params = {}) // (1)
{}
A(std::initializer_list<int>) // (2)
{}
...
};
class B {
public:
B() = default;
private:
A a{1, 2, From_params{}}; // calls (1)
};

How does the compile choose which constructor to call?

This is my code.
When I delete line 11, the output is
A(0)
B(0)
A(1)
about the last line, "A(1) ", why the second constructor of class A is called?
#include <iostream>
using namespace std;
class A {
public:
A() { cout << "A(0)" << endl; }
A(const A& a) { cout << "A(1)" << endl; }
};
class B {
public:
B() : a() { cout << "B(0)" << endl; }
// B(const B& b) { cout << "B(1)" << endl; }
private:
A a;
};
int main() {
B object1;
B object2 = object1;
return 0;
}
A(0)
B(0)
A(1)
When
B(const B& b) { cout << "B(1)" << endl; }
is commented out/deleted the compiler generates a copy constructor for you. This provided copy constructor will copy all of the members of the class so in this case it will stamp out a copy constructor that looks like
B(const B& copy) : a(copy.a) {}
This is why you see a's copy constructor called.
When you do not comment out/delete
B(const B& b) { cout << "B(1)" << endl; }
You do not copy a because you do not tell it to do so. What the compiler does instead is creates a default initialization for it by transforming the constructor to
B(const B& b) : a() { cout << "B(1)" << endl; }
so the default constructor is called instead of the copy constructor.
The compiler is generating a copy constructor for you, which copies the member a. In order to copy member a, it calls its copy constructor in turn, which prints A(1).
Because object2 is initialized with the implicit copy constructor of B. An implicit copy constructor implicitly copy all the data members of the class, hence the call of the copy constructor of A, which prints "A(1)".
The issue you've run into has to do with thinking commenting out line 11 means you've deleted that constructor.
In C++, there are a couple of constructors that are automatically generated if you ended up using them, even if you didn't declare them yourself. The copy-constuctor, which has the same signature as the commented-out constructor in B, is one of them.
In your case, you end up first calling the default constructor for B, which first constructs it's member A using the default constructor as well. This should give the output you see, where the body of A's copy-constructor is reached before the body of B's because of member initialization ordering.
Then, you make a new object of type B using the assignment operator which implicitly calls the now-generated copy constructor of B. That means A's copy constructor gets called as well, which is a rule in how B's copy-constructor is auto generated. With A's copy-constuctor un-commented, it gets called with the printout.
The compiler for the class B (with the commented copy constructor) defines implicitly the default copy constructor that calls copy constructors for class members.
From the C++ 20 Standard (11.3.4.2 Copy/move constructors)
14 The implicitly-defined copy/move constructor for a non-union class
X performs a memberwise copy/move of its bases and members...
The implicitly defined default copy constructor of the class B looks like
B( const B &b ) : a( b.a )
{
}
Here is a demonstrative program
#include <iostream>
using namespace std;
class A {
public:
A() { cout << "A(0)" << endl; }
A(const A& a) { cout << "A(1)" << endl; }
};
class B {
public:
B() : a() { cout << "B(0)" << endl; }
// An analogy of the implicitly declared copy constructor
B(const B& b) : a( b.a ){}
private:
A a;
};
int main() {
B object1;
B object2 = object1;
return 0;
}
The program output will be the same as if to remove the copy constructor of class B that corresponds to the implicitly generated copy constructor by the compiler.
A(0)
B(0)
A(1)

why does adding a move constructor disable initializier list?

With a simple struct such as
struct Foo { int i; };
I can create a new instance using an initializer list; no need to write a constructor:
Foo foo { 314 };
If I now add a move constructor
struct Bar
{
int i;
Bar(Bar&& other) { i = other.i; }
};
The initializer no longer works and I have to add a constructor too:
Bar(int i) : i(i) {}
I'm guessing this behavior is somewhat related to this answer (for user-defined move-constructor disables the implicit copy-constructor?), but more details would be nice.
Edit: as indicated by the answers, this has to do with adding a constructor. Which in turn would seem to create an inconsistency of sorts, if I add just a move operator:
struct Baz
{
int i;
Baz& operator=(Baz&& other)
{
this->i = other.i;
return *this;
}
};
The initializer works again, although with a slightly different syntax for "move" (yes, this is actually default construct and move assignment; but the end result seems about the same):
Baz baz{ 3141 };
Baz b;
b = std::move(baz);
When there are no constructors this syntax is aggregate initialization because this structure is an aggregate.
When a constructor is added this structure is no longer an aggregate, aggregate initialization cannot be used. The exact rules are listed in list initialization, the relevant ones are:
The effects of list initialization of an object of type T are:
Otherwise, if T is an aggregate type, aggregate initialization is performed.
Otherwise, the constructors of T are considered, in two phases:...
It is not initializer list construction that is disabled by the move constructor (that was not present there to start with), but aggregate construction. And for a good reason: by adding a custom constructor, we indicate to the compiler exactly that the class in not an aggregate, that something different is necessary than just operate on each of its members one by one.
For an aggregate, the default default, copy, and move constructor will work well even if the member variables have nontrivial types. A copy construction will automatically be deleted if it can't be delegated to them, leaving move construction usable:
struct A { // non-copyable
int a;
int b;
A(int a_, int b_): a(a_), b(b_) { std::cout << "A(int,int)\n"; }
A() { std::cout << "A()\n"; }
A(const A&) = delete;
A(A&&) { std::cout << "A(A&&)\n"; }
};
struct B {
A a;
};
int main() {
B b1{{1,2}}; // OK: aggregate
B b2{std::move(b1)}; // OK: calls A::A(A&&)
//B b3{b1}; // error: B::B(const B&) auto-deleted
}
However, if you want to delete copy construction for some other reason and keep the others at default, just be explicit about it:
struct A { // copyable
int a;
int b;
A(int a_, int b_): a(a_), b(b_) { std::cout << "A(int,int)\n"; }
A() { std::cout << "A()\n"; }
A(const A&) { std::cout << "A(const A&)\n"; }
A(A&&) { std::cout << "A(A&&)\n"; }
};
struct B { // non-copyable
A a;
B() = default;
B(const B&) = delete;
B(B&&) = default;
};
int main() {
B b1{{1,2}}; // OK: still an aggregate
B b2{std::move(b1)}; // delegates to A::A(A&&)
//B b3{b1}; // error
}
Because you're using aggregate initialization, which says:
Aggregate initialization is a form of list-initialization, which
initializes aggregates An aggregate is one of the following types:
array type class type (typically, struct or union), that has
no private or protected non-static data members
no user-provided,
inherited, or explicit (since C++17) constructors (explicitly
defaulted or deleted constructors are allowed) (since C++11)
no
virtual, private, or protected (since C++17) base classes
no virtual
member functions
Point 2 makes your case fail.

Is it valid to copy an inherited member in the derived class constructor?

In the below code I have defined an explicit copy constructor in the derived class. I have also written my own copy constructor in the base class.
Primer says that the derived copy constructor must call the base one explicitly and that inherited members should be copied by the base class copy constructor only, but I copied the inherited members in the derived class copy constructor and it is working fine. How is this possible?
Also how do I explicitly call the base class copy constructor inside the derived class copy constructor? Primer says base(object), but I am confused how the syntax differentiates between normal constructor call and copy constructor call.
Thanks in advance.
#include<stdafx.h>
#include<iostream>
using namespace std;
class A
{
public:
int a;
A()
{
a = 7;
}
A(int m): a(m)
{
}
};
class B : public A
{
public:
int b;
B()
{
b = 9;
}
B(int m, int n): A(m), b(n)
{
}
B(B& x)
{
a = x.a;
b = x.b;
}
void show()
{
cout << a << "\t" << b << endl;
}
};
int main()
{
B x;
x = B(50, 100);
B y(x);
y.show();
return 0;
}
copy constructor is when you have another Object passed to your constructor:
class A() {
private:
int a;
public:
//this is an empty constructor (or default constructor)
A() : a(0) {};
//this is a constructor with parameters
A(const int& anotherInt) : a(anotherInt) {};
//this is a copy constructor
A(const A& anotherObj) : a(anotherObj.a) {};
}
for a derived class
class B : public A {
private:
int b;
public:
//this is the default constructor
B() : A(), b() {};
//equivalent to this one
B() {};
//this is a constructor with parameters
// note that A is initialized through the class A.
B(const int& pa, const int& pb) : A(pa), b(pb) {}
//for the copy constructor
B(const B& ob) : A(ob), b(ob.b) {}
}
How somebody else wrote here:
How to call base class copy constructor from a derived class copy constructor?
I would write the copy constructor like this instead how it was written by macmac:
B(const B& x) : A(x) , b(x.b)
{
}
To call the copy constructor of the base A you simply call it passing the derived B object A(B), is not neccessary to specify B.a.
EDIT: macmac edited his answere in the correct way, now his answere is better then mine.

How to initialize a class member data with other member data of this class ?

I have class A and B.
B is a member of A.
I need to initialize B with other data members of A.
class A;
class B
{
public:
B(A& a){cout << "B constr is run \n";}
};
class A
{
public:
A(){}
void initB(A& a){b(a); cout << "A call init B \n"; }
private:
// other members ...
B b;
};
int main()
{
A a;
a.initB(a);
}
I got compile error:
classIns.cpp: In constructor âA::A()â:
classIns.cpp:14: error: no matching function for call to âB::B()â
classIns.cpp:8: note: candidates are: B::B(A&)
classIns.cpp:6: note: B::B(const B&)
classIns.cpp: In member function âvoid A::initB(A&)â:
classIns.cpp:16: error: no match for call to â(B) (A&)â
Why A(){} needs to call B::B() ?
How to initialize B with other data members of A ?
thanks
B has no default constructor, which means you have to initialise it in A's ctor.
struct A {
A() : b(*this) {}
private:
B b;
};
Any time you think of using init-like members, you're probably doing it wrong. Object should always be valid after the constructor is done.
You can use initialization chain in A constructor:
class B
{
public:
B(Type1 x, Type2 y)
{
}
void init(Type1 x, Type2 y) { ........}
};
class A
{
public:
A() : Amember1(), Amember2(), b(Amember1, Amember2) {}
private:
Type1 Amember1;
.....
B b;
};
But you can't invoke B constructor inside initB method because b is already constructed.
You can use a B::init() method with A data, like:
void A::initB(A& a){ b.init(a.Amember1, a.Amember2); cout << "A call init B \n"; }
Like this :
void initB(A& a){
b = B(a);
cout << "A call init B \n";
}
Off course, the class B needs a default constructor, and a copy constructor that takes reference to the object of type A.
Why A(){} needs to call B::B() ?
Because A has a data member B which needs to be initialized when you create an instance of the A class. In your case b is initialized with the default B c'tor.
Since you are specifying a constructor for B
public:
B(A& a){cout << "B constr is run \n";}
The default constructor :
B(){}
is not automatically generated by the compiler. So it complains.