c++: initialization list with no default constructor - c++

If I have a class A without default constructor and a class B
class B {
private:
A m_a;
public:
B(A a) : m_a(a) {}
};
How is m_a now initialized?
By the assignment operator of A or by the copy constructor?

By the copy constructor, since it's being copy-initialised.
The assignment operator is used for assignment to an existing object, never for initialisation of a new object.

Related

assign member of the derived class to another of the derived class

i have a question about assigning one member of the derived class to another of the same derived class,
Can someone please help me understand why this code is printing 14 and not 34?
i dont understand when b2.nb is getting the value of b1.nb, because in this code:
A& operator=(const A& a){
na = a.na*2;
return *this;
}
there is no assignment of b1.nb to b2.nb
class A{
public:
A(int i){na = i;}
A& operator=(const A& a){
na = a.na*2;
return *this;
}
int na;
};
class B : public A{
public:
B(int i, int j): A(j){nb = i;}
int nb;
};
int main()
{
B b1(1,2);
B b2(3,4);
b2 = b1;
cout<<b2.nb<<b2.na;
}
From cppreference
Implicitly-declared copy assignment operator
If no user-defined copy assignment operators are provided for a class type (struct, class, or union), the compiler will always declare one as an inline public member of the class.
Your B class never declares a copy assignment operator (i.e. an operator with a signature compatible with B& operator=(const B&)). The fact that A does is irrelevant here. B does not declare one, so C++ generates one. That generated copy assignment operator calls the parent class' assignment operator and then assigns any variables declared in B directly, in your case nb.

Copy constructor and assignment operators with polymorphism

Just failed an interview because of this, and I'm still confused:
class A
{
public:
A(int a) : a_(a) {}
// Copy constructor
// Assignment operator
private:
int a_;
};
class B : public A
{
public:
B(int a, int b) : A(a), b_(b) {
}
// Copy constructor
// Assignment operator
private:
int b_;
};
How do you implement the copy constr/assignment op, and why does the constructor of B have to have an A initialized in the initializer list? It doesn't work if it's not in the list.
How do you implement the copy constr/assignment op
Trick question, I think. In this case the best option is to do absolutely nothing. Neither class contains (and owns) any resources requiring more than the default special member functions. Observe the Rule of Zero.
Some style guides recommend explicitly defaulting special member functions. In this case
class A
{
public:
A(int a) : a_(a) {}
A(const A &) = default;
A& operator=(const A &) = default;
private:
int a_;
};
may be appropriate.
why does the constructor of B have to have an A initialized in the initializer list?
All class members and base classes must be fully constructed before entering the body of a constructor.
B(int a, int b)
{ // Entering constructor's body. A must be constructed before we get here.
}
A has no default constructor, so the constructor it does have must be explicitly called in the initializer list to construct the base class before the construction of B can proceed.
Addressing comment
A's copy constructor and assignment operator are trivial:
A(const A & src): a_(src.a_)
{
}
A& operator=(const A & src)
{
a_ = src.a_;
return *this;
}
B is a bit trickier because it also has to make sure A is copied
B(const B & src): A(src), // copy the base class
b_(src.b_)
{
}
B& operator=(const B & src)
{
A::operator=(src); // assign the base class by explicitly calling its
// assignment operator
b_ = src.b_;
return *this;
}
Note: If I were hiring, I'd take the programmer who called me out on the trick question over the programmer who did the extra work and risked an unforced error.
why does the constructor of B have to have an A initialized in the
initializer list?
A only has one constructor which takes an int. B has A as a base class, which means that every B object must first construct an A object. How else are you going to construct that A object with it's required parameter except by using an initialiser list?

basic constructor with vector : Inappropriate default constructor

Here is the code to demonstrate the classic problem
class A
{
public:
A(int){}
};
class B
{
vector<A> va; //Error no default constructor available
public:
B(vector<A>v):va(v)
{}
};
The error is no default constructor available. I don't need default constructor for class A, so don't write it.
Adding a trivial constructor for A will work for you
class A
{
public:
A(int) {}
A() {}
};

Default constructor missing for a nested class in the copy constructor of a parent class

I have a nested class structure, Class A is parent and Class B is nested under.
When I compile the code, the copy constructor of Class A reports that there is no default constructor for the class B.
error: no default constructor exists for class "A::B"
class A{
-------
struct B{
B(var1, var2){}
};
B b;
};
A::A(){ b = new B(Var1, Var2) } // default constructor
A::A(a){ } // copy constructor
Any ideas on how to fix this ?
You need to use a member initializer in both constructors:
A::A() : b(Var1, Var2) {}
A::A(const A& a) : b(Var1, Var2) {}
You defined a constructor taking two arguments B(var1, var2) as such a default constructor is not automatically provided for you.
So you have a couple of options.
Choice 1
Add a default constructor for b in your struct B definition
struct B{
....
B() {};
}
also your syntax below is wrong it should be:
A::A() : b() {};
A::A( const A& a) : b() {};
Choice 2
You could use the non default constructor of B but you have to come up with values from somewhere
A::A() : B( valA, valB ) {};
A::A( const A& a) : b(valA, valB) {};
Choice 3
You probably don't want that and instead should create a copy constructor for B and do this
A::A( const A& a) : b(a.b) {};

Why do "normal" implementations of copy/move functions in derived classes behave differently depending on how they're defined?

I'm confused about the behavior I'm seeing when derived class copy and move functions call their base class versions.
I have a base class with various constructors that tell me when they're called:
#include <iostream>
class Base {
public:
Base() {}
template<typename T>
Base(T&&) { std::cout << "URef ctor\n"; }
Base(const Base&) { std::cout << "Copy ctor\n"; }
Base(Base& rhs): Base(const_cast<const Base&>(rhs))
{ std::cout << " (from non-const copy ctor)\n"; }
Base(Base&&) { std::cout << "Move ctor\n"; }
Base(const Base&& rhs): Base(rhs)
{ std::cout << " (from const move ctor)\n"; }
};
For a derived class with compiler-generated copy and move operations
class Derived: public Base {};
and this test code,
int main()
{
Derived d;
Derived copyNCLValue(d);
Derived copyNCRvalue(std::move(d));
const Derived cd;
Derived copyCLValue(cd);
Derived copyCRvalue(std::move(cd));
}
gcc 4.8.1 produces this output:
Copy ctor
Move ctor
Copy ctor
Copy ctor
This surprises me. I expected the base class constructor taking the universal reference to be called, because it can be instantiated to create an exact match on the derived object that is presumably passed from the derived class's functions. The base class copy and move functions require a derived-to-base conversion.
If I change the derived class to declare the copy and move functions myself, but to give them the default implementations,
class Derived: public Base {
public:
Derived(){}
Derived(const Derived& rhs) = default;
Derived(Derived&& rhs) = default;
};
gcc produces the same output. But if I write the functions myself with what I believe are the default implementations,
class Derived: public Base {
public:
Derived(){}
Derived(const Derived& rhs): Base(rhs) {}
Derived(Derived&& rhs): Base(std::move(rhs)) {}
};
I get the output I originally expected:
URef ctor
URef ctor
URef ctor
URef ctor
I'd expect to get the same output in each case. Is this a bug in gcc, or is there something I'm not understanding?
This surprises me. I expected the base class constructor taking the universal reference to be called, because it can be instantiated to create an exact match on the derived object that is presumably passed from the derived class's functions. The base class copy and move functions require a derived-to-base conversion.
No. The compiler sees the line Derived copyCRvalue(std::move(cd)); that really means Derived copyCRvalue(static_cast<const Derived&&>(cd)); and it tries to find a constructor in Derived that matches that call. It finds two closely related constructors both implicitly declared:
Derived(Derived const &); // copy constructor
Derived(Derived &&); // move constructor
The second one cannot be used, since the rvalue-reference is to a const object, but the first one is a match. The definition of the implicitly defined copy constructor is:
Derived(Derived const &rhs) : base(static_cast<Base const &>(rhs)) {}
Inside the constructor, the rhs is an lvalue, not an rvalue (and a templated constructor is not a copy-constructor anyways).
But if I write the functions myself with what I believe are the default implementations,
class Derived: public Base {
public:
Derived(){}
Derived(const Derived& rhs): Base(rhs) {}
Derived(Derived&& rhs): Base(std::move(rhs)) {}
};
Except that those are not the definitions that the compiler will provide. The specific quota from the standard is in 12.8/15
The implicitly-defined copy/move constructor for a non-union class X performs a memberwise copy/move of its bases and members.
That is, the implicitly defined constructor will initialize the destination's base with the source's base, and similarly each member in the destination with the same member in the source.