confusion in constructor calling in virtual function - c++

Confusion in constructor calling via temporary object as argument in a function
#include <iostream>
using namespace std;
class Base
{
protected:
int i;
public:
Base() {
cout<<"\n Default constructor of Base \n";
}
Base(int a)
{
i = a;
cout<<"Base constructor \n";
}
void display(){
cout << "\nI am Base class object, i = " << i ;
}
~Base(){
cout<<"\nDestructor of Base\n";
}
};
class Derived : public Base
{
int j;
public:
Derived(int a, int b) : Base(a) {
j = b;
cout<<"Derived constructor\n";
}
void display() {
cout << "\nI am Derived class object, i = "<< i << ", j = " << j;
}
~Derived(){
cout<<"\nDestructor Of Derived \n";
}
};
void somefunc (Base obj) //Why there is no call to default constructor of Base class
{
obj.display();
}
int main()
{
Base b(33);
Derived d(45, 54);
somefunc( b) ;
somefunc(d); // Object Slicing, the member j of d is sliced off
return 0;
}
My question is that why there is no call to Default Constructor of Base Class,when we are creating a Temporary object of a Base class in function ( void somefunc(Base obj) )

My question is that why there is no call to Default Constructor of Base Class,when we are creating a Temporary object of a Base class in function
An instance of Base is constructed using the copy constructor when the call to somefunc is made. That object is not constructed using the default constructor. A default copy constructor is created by the compiler since you haven't defined one.

It's not a temporary object. The argument is passed by value to the function, so the copy ctor will be called, not default ctor. Note that compiler will provide a copy constructor if there is no user defined, you can define it by yourself to output some debug info.
Base(const Base& a) : i (a.i)
{
cout<<"Base copy constructor \n";
}

it will call copy construct function to create the Temporary object of a Base class in function

Related

Defaulted destructor in base class disable move constructor in child class if there is a member

Why does defaulted (user declared) destructor in Base1 prevent generation of move constructor/operator in Child1 class, but everything work fine when I move member data from Base (Base2) to Child (Child2) class?
struct Data {
Data() {}
Data(Data&&) noexcept { cout << "Move constructor" << endl; }
Data& operator=(Data&&) noexcept {
cout << "Move assign" << endl;
return *this;
}
vector<int> vec;
};
struct Base1 {
virtual void fun() { cout << "Base1::fun" << endl; }
virtual ~Base1() = default;
Data data;
};
struct Child1 : public Base1 {
void fun() override { cout << "Child1::fun" << endl; }
};
struct Base2 {
virtual void fun() { cout << "Base2::fun" << endl; }
virtual ~Base2() = default;
};
struct Child2 : public Base2 {
void fun() override { cout << "Child2::fun" << endl; }
Data data;
};
int main() {
Child1 c1;
auto obj1 = std::move(c1); // error
Child2 c2;
auto obj2 = std::move(c2);
}
My current understanding is that when I declare destructor as “default” in Base (BaseDel), then move constructor should be “deleted” in Base (BaseDel) and in Child (ChildDel) class. Is this correct? Member location shouldn’t matter, I think. If I do that explicit, I get expected error:
struct BaseDel {
BaseDel() {}
virtual void fun() { cout << "BaseDel::fun" << endl; }
BaseDel(BaseDel&& st) = delete;
virtual ~BaseDel() = default;
};
struct ChildDel : public BaseDel {
ChildDel() {}
void fun() override { cout << "ChildDel::fun" << endl; }
Data data;
};
int main() {
ChildDel cd;
auto objd = std::move(cd); // OK, expected error
}
The implicit move constructor is not (only) deleted, it is not declared in the first place when you have a user-declared destructor, as is the case with Base1 and Base2.
Therefore the move constructor can never be considered in overload resolution and so auto obj1 = std::move(c1);, while it can call Child1's move constructor, needs to fall back to copy construction for the Base1 subobject.
The implicitly-declared copy constructors of both Base1 and Child1 are defined as deleted, because Data's implicitly-declared copy constructor is defined as deleted, because Data has a user-defined move constructor. Therefore auto obj1 = std::move(c1); will fail with an error that the implicitly-declared copy constructor is deleted.
For Base2 the copy constructor is not defined as deleted, because it doesn't have a Data member and so auto obj2 = std::move(c2); will call Child2's move constructor (which also uses Data's move constructor), but use the copy constructor for the Base2 subobject.

Copy constructing from a derived object

In the following code, the function foo is copy constructing a Base object c from a Derived object d. My question is: are we getting an exact copy? Because I'm not getting the polymorphic behavior I'm expecting
#include<iostream>
class Base
{
public:
virtual void sayHello()
{
std::cout << "Hello Base" << std::endl ;
}
};
class Derived: public Base
{
public:
void sayHello() override
{
std::cout << "Hello Derived" << std::endl ;
}
};
void foo(Base* d)
{
Base* c = new Base(*d);
c->sayHello() ;
}
int main()
{
Derived d;
foo(&d) ; //outputs Hello Base
}
There is no virtual constructor nor copy constructor.
However, it is possible to define a function that behaves like one.
In my case, it is the virtual member function copy() which I added to OP's sample:
#include <iostream>
class Base
{
public:
virtual Base* copy() const { return new Base(*this); }
virtual void sayHello()
{
std::cout << "Hello Base" << std::endl ;
}
};
class Derived: public Base
{
public:
virtual Base* copy() const override { return new Derived(*this); }
void sayHello() override
{
std::cout << "Hello Derived" << std::endl ;
}
};
void foo(Base* d)
{
Base* c = d->copy();
c->sayHello() ;
}
int main()
{
Derived d;
foo(&d) ; //outputs Hello Derived
return 0;
}
Output:
Hello Derived
Live Demo on coliru
The drawback is that every derived class of Base has to provide it to make it function properly. (I've no idea how to convince the compiler to check this for me with any trick.)
A partial solution could be to make copy() pure virtual in the class Base (assuming it is not meant to be instantiable).
you may wonna change the line of new
Base* c = new Derived(*d);
so you have the type Derived in a Base pointer. During runtime it is looked up, which type it is and you get the right output.
let me know if im wrong... just created this out of my mind on the fly.
To answer your question about whether or not this is copy constructing lets add some members. Base will have a member, m_b and Derived will inherit m_b but also have another member m_d
#include <iostream>
struct Base {
const int m_b;
Base() = delete;
Base(const int a_b) : m_b(a_b) {}
virtual void sayHello() {
std::cout << "Base " << m_b << std::endl;
}
};
struct Derived : public Base {
const int m_d;
Derived() = delete;
Derived(const int a_b, const int a_d) : Base(a_b), m_d(a_d) {}
void sayHello() override {
std::cout << "Derived " << m_b << ' ' << m_d << std::endl;
}
};
void foo(Derived* a) {
Base* b = new Base(*a);
b->sayHello(); // Output is "Base 1", 1 was copied from argument a
}
void bar(Derived* a) {
Base* d = new Derived(*a);
d->sayHello(); // Output is "Derived 1 2"
}
int main() {
Derived d(1, 2);
foo(&d);
bar(&d);
return 0;
}
The line:
Base* b = new Base(*a);
Created a Base and so sayHello calls Base's implementation which doesn't know about m_d. However this line does copy m_b from the derived class
The line:
Base* d = new Derived(*a);
Created a Derived and so sayHello calls Derived's implementation which copied both m_b and m_d
Expected polymorphic behavior will come into existence when the Base class pointer points to Derived class object. Then at run time the actual type of object pointed to by the Base class pointer will be checked and appropriate function will get called.
Base* c = new Base(*d); // <<-- case of object slicing
Here, c points to Base class object. Therefore, c->sayHello() ; is bound to call the Base::sayHello() at runtime.
are we getting an exact copy?. No since you are creating a Base object due to new Base. Due to object slicing the Base part of the *d object is passed to copy c'tor and what you get is corresponding Base object.
Base *c = new Derived(*d); will give the expected behavior.

Initializing a base class that has the same name as a member variable

Given that I have:
a base class called A
a constructor for A that takes an int argument
a subclass called B that inherits from A
a member variable of class B that is an int and is called A
How do I call the constructor A::A(int) in B's constructor? It seems that all I can do is initialize the member variable called A.
Her's a short code reproducing the issue:
#include <iostream>
class A
{
public:
A();
A(int);
};
class B : public A
{
public:
B();
int A = 100;
};
A::A()
{
std::cout << "in constructor A";
}
A::A(int s)
{
std::cout << "value in A constructor " << s;
}
// Here I want to initialize the base class with 50
// and the member with 78. Is it possible?
B::B() : A(50), A(78)
{
std::cout << "in Constructor B";
std::cout << A;
}
int main()
{
B b;
}
I want to initialize class member A with 78, and call the base class constructor with 50. How can I do that?
If I try to assign to the member instead:
B::B() : A(50)
{
A = 78;
std::cout << "in Constructor B";
std::cout << A;
}
the output is
in constructor Ain Constructor B78
It's not calling the A::A(int) overloaded constructor.

C++ base class constructor with default parameters

I wrote this small program to test my understanding. What I'm having trouble understanding is that constructors aren't inherited, but class B is able to call the constructor of class A!
#include <iostream>
using namespace std;
class A {
public:
A(int x = 2) { //Constructor A
num = x;
}
int getNum() {
return num;
}
protected:
int num;
};
class B: public A { //Constructor B
public:
B() {
A(5);
}
};
int main() {
A a(3); //create obj a with num = 3
B b; //create obj b
cout << a.getNum() << endl;
cout << b.getNum() << endl;
return 0;
}
The output is:
3
2
What did the constructor A's call do exactly? It didn't use the passed argument to initialize object b's number!
Furthermore, if I remove the default value from class A's constructor, I get compilation error:
no matching function for call to 'A::A()'
So what's exactly happening here?
I know that the correct way is to do so:
class B: public A { //Constructor B
public:
B() : A(5) {
}
};
Which gives the output:
3
5
But this is just for the purpose of understanding.
Lets take a look at the B constructor:
B() {
A(5);
}
Here you actually "call" the A constructor twice. Once as part of the B construction (where the "default" A constructor is called), and once as you create a temporary object inside the B constructor body.
The sequence is as
B constructor called
A default constructor called as part of the initialization of the B object
The body of the B constructor is entered
A non-default constructor called (with argument 5) as part of creation of the temporary object
The temporary object goes out of scope and is destructed
The body of the B constructor exits

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.