In the following code, when I initialize a subclass with an argument of the same class, the program calls the parent class constructor but not the subclass's [derived3]. However, if I pass in an argument belonging to just the parent class, it calls both functions correctly [derived2]. Why would the compiler ignore the subclass constructor in the former case?
#include <iostream>
class Base {
public:
Base() {
std::cout << "Base constructor" << std::endl;
}
Base(Base& b) {
std::cout << "Base parameterized constructor" << std::endl;
}
};
class Derived : public Base {
public:
Derived() {
std::cout << "Derived constructor" << std::endl;
}
Derived(Base& b) : Base(b) {
std::cout << "Derived parameterized constructor" << std::endl;
}
};
int main(int argc, char **argv) {
std::cout << "[base]" << std::endl;
Base base {};
std::cout << "[derived]" << std::endl;
Derived derived {};
std::cout << "[base2]" << std::endl;
Base base2 {base};
std::cout << "[derived2]" << std::endl;
Derived derived2 {base};
std::cout << "[base3]" << std::endl;
Base base3 {derived};
std::cout << "[derived3]" << std::endl;
Derived derived3 {derived};
}
Output:
[base]
Base constructor
[derived]
Base constructor
Derived constructor
[base2]
Base parameterized constructor
[derived2]
Base parameterized constructor
Derived parameterized constructor
[base3]
Base parameterized constructor
[derived3]
Base parameterized constructor
When you do
Derived derived3 {derived};
You are making a copy, so the copy constructor is called. Since you did not override the copy constructor with your own that prints a statement, you only see the base copy constructor get called.
Adding
Derived(Derived& d) : Base(d) {
std::cout << "Derived copy constructor" << std::endl;
}
will give you two print statements for the derived3 line.
That's because Base(Base& b) is not a regular parameterized constructor. It's a copy constructor.
This is a special type of constructor and is handled specially. derived3 calls both Derived copy constructor (implicitly declared by compiler) and Base copy constructor (declared by you).
Related
I know and I have read many threads to call a base class constructor from a Derived class, But I wanted to implement it using Delegating constructors
Here is my code
The error states
"A delegating constructor cannot have other mem-initializers"
#include <iostream>
using namespace std;
// Shivang101
class Base
{
private:
int value;
public:
Base() : value{0}
{
cout << "Base no args constructor called" << endl;
}
Base(int x) : value{x}
{
cout << "Base (int) overloaded constructor called" << endl;
}
~Base()
{
cout << "Base Destructor called" << endl;
}
};
class Derived : public Base
{
private:
int testing_value;
int doubled_value;
// using Base ::Base;
public:
Derived() : Derived{0, 0}
{
cout << "NO arg constructor called" << endl;
};
// In the below line I'm Trying a call the base class constructor but getting error
Derived(int testing_val) : Base{testing_val}, Derived{testing_val, 0}
{
cout << "One arg constructor called" << endl;
}
Derived(int testing_val, int doubled_val) : testing_value{testing_val}, doubled_value{doubled_val}
{
cout << "Delegating constructor/ overloaded called" << endl;
}
~Derived()
{
cout << "Derived destructor called" << endl;
}
};
int main()
{
Derived d{1000};
return 0;
}
I wanted to call my base class constructor and initialize the "value" in Base class as "1000" and initialize the "testing_*value" and "doubled_*value" in the Derived class as "1000" and "2000" respectively
A constructor is responsible for initializing all members and base subobjects.
A delegating constructor delegates to a different constructor.
It cannot be both. Either you delegate elsewhere or you initialize members and base subobjects.
Quoting from cppreference:
Delegating constructor
If the name of the class itself appears as class-or-identifier in the
member initializer list, then the list must consist of that one member
initializer only; such a constructor is known as the delegating
constructor, and the constructor selected by the only member of the
initializer list is the target constructor
I suppose you can rearrange the constructors to achieve desired effect. Though I don't see how it can be done without implementing one more constructor or change the way of delegating, because currently the one taking two arguments calls the default constructor of Base, but the one delegating to it attempts to call Base{testing_val}.
I Found the solution to my Question
We can call the Base Class Constructor from Derived Class using Delegating constructor by calling the Base class constructor in the delegating constructor itself
In the I was passing Base Class constructor call from overload to delegating constructor
No I have called Base Class Constructor from the Delegating constructor itself
#include <bits/stdc++.h>
using namespace std;
// Shivang101
class Base
{
private:
public:
int value;
int value2;
Base() : value{0}
{
cout << "Base no args constructor called" << endl;
}
Base(int x) : value{x}
{
cout << "Base (int) overloaded constructor called" << endl;
}
~Base()
{
cout << "Base Destructor called" << endl;
}
};
class Derived : public Base
{
private:
public:
int testing_value;
int doubled_value;
// using Base ::Base;
Derived() : Derived{0, 0}
{
cout << "NO arg constructor called" << endl;
};
Derived(int testing_val) : Derived{testing_val, 0}
{
cout << "One arg constructor called" << endl;
}
Derived(int testing_val, int doubled_val) : Base{testing_val}, testing_value{testing_val}, doubled_value{doubled_val * 2}
{
cout << "Delegating constructor/ overloaded called" << endl;
}
~Derived()
{
cout << "Derived destructor called" << endl;
}
};
int main()
{
Derived d{1000};
cout << d.value << endl;
return 0;
}
```
I understand that you can't expect to have a derived reference pointing at its base class because it will lose functionality, but I was curious on what would actually happen to understand more about the sequence of events.
#include <iostream>
struct Base
{
Base() { std::cout << "Base constructor" << std::endl; }
Base(const Base&) { std::cout << "Base copy constructor" << std::endl; }
~Base() { std::cout << "Base destructor" << std::endl; }
};
struct Derived : public Base
{
Derived(const Base& b) : Base(b) { std::cout << "Derived constructor" << std::endl; }
~Derived() { std::cout << "Derived destructor" << std::endl; }
};
struct OwnsDerived
{
OwnsDerived(const Derived& derivedObject) : derivedRef(derivedObject) { std::cout << "OwnsDerived created..." << std::endl; }
const Derived& derivedRef;
};
int main () {
std::cout << "Main starts: " << std::endl;
const Base b;
std::cout << "\nMain creating object that owns a reference to derived: " << std::endl;
OwnsDerived s(b);
std::cout << "\nMain ends: " << std::endl;
return 0;
}
The result I got was:
Main starts:
Base constructor
Main creating object that owns a reference to derived:
Base copy constructor
Derived constructor <-- why is a derived trying to be created when passing the wrong type in the constructor
OwnsDerived created...
Derived destructor //<-- these are treated as temporaries
Base destructor //<--
Main ends:
Base destructor
Even when I change the reference to be a copy of the object instead, it behaves similarly, which is also surprising to me.
I would really appreciate any pointers or any resources to learn about the more nuanced mechanics of these constructor/destructors!
OwnsDerived constructor takes a Derived by reference to const, but you pass a Base instance. So, the compiler will try to convert the Base instance to a Derived. That's possible by calling the (implicit) conversion constructor in Derived. So, a temporary instance of Derived is created.
To fix the implicit conversion, declare the Derived constructor as explicit.
struct Derived : public Base
{
explicit Derived(const Base& b);
//...
};
Reference to this https://www.tutorialspoint.com/cplusplus/cpp_functions.htm
In CPP when ever you call a function, it will copy the paramenter of that function instead of using it directly
So, when you call the contructor of OwnsDerived it use const Base b as it paramenter. The system will copy this to other memory where you get this log Base copy constructor. I will call this a copied_b. So copied_b is Base it will convert it to Derive as the contructor of OwnsDerived required a Derive so there is Derived constructor. I call this derived_of_copied_b. At the end of the contructor of OwnsDerived both copied_b and derived_of_copied_b will be destroy, where you will see Derived destructor and Base destructor right after OwnsDerived created....
I wish this could explain your question.
I don't understand why in the following code, when I instanciate an object of type daughter, the default grandmother() constructor is called ?
I thought that either the grandmother(int) constructor should be called (to follow the specification of my mother class constructor), or this code shouldn't compile at all because of the virtual inheritance.
Here compiler silently calls grandmother default constructor in my back, whereas I never asked for it.
#include <iostream>
class grandmother {
public:
grandmother() {
std::cout << "grandmother (default)" << std::endl;
}
grandmother(int attr) {
std::cout << "grandmother: " << attr << std::endl;
}
};
class mother: virtual public grandmother {
public:
mother(int attr) : grandmother(attr) {
std::cout << "mother: " << attr << std::endl;
}
};
class daughter: virtual public mother {
public:
daughter(int attr) : mother(attr) {
std::cout << "daughter: " << attr << std::endl;
}
};
int main() {
daughter x(0);
}
When using virtual inheritance, the virtual base class's constructor is called directly by the most derived class's constructor. In this case, the daughter constructor directly calls the grandmother constructor.
Since you didn't explicitly call grandmother constructor in the initialization list, the default constructor will be called. To call the correct constructor, change it to:
daugther(int attr) : grandmother(attr), mother(attr) { ... }
See also This FAQ entry.
I don't understand why in the following code, when I instanciate an object of type daughter, the default grandmother() constructor is called ?
I thought that either the grandmother(int) constructor should be called (to follow the specification of my mother class constructor), or this code shouldn't compile at all because of the virtual inheritance.
Here compiler silently calls grandmother default constructor in my back, whereas I never asked for it.
#include <iostream>
class grandmother {
public:
grandmother() {
std::cout << "grandmother (default)" << std::endl;
}
grandmother(int attr) {
std::cout << "grandmother: " << attr << std::endl;
}
};
class mother: virtual public grandmother {
public:
mother(int attr) : grandmother(attr) {
std::cout << "mother: " << attr << std::endl;
}
};
class daughter: virtual public mother {
public:
daughter(int attr) : mother(attr) {
std::cout << "daughter: " << attr << std::endl;
}
};
int main() {
daughter x(0);
}
When using virtual inheritance, the virtual base class's constructor is called directly by the most derived class's constructor. In this case, the daughter constructor directly calls the grandmother constructor.
Since you didn't explicitly call grandmother constructor in the initialization list, the default constructor will be called. To call the correct constructor, change it to:
daugther(int attr) : grandmother(attr), mother(attr) { ... }
See also This FAQ entry.
If I make a size 2 std::vector of a derived class, the constructor is called only once. If I make a size 2 vector of a base class, the constructor is called twice.
I usually wouldn't post the complete code that duplicates an issue, but in this case it can be made quite short:
#include <iostream>
#include <vector>
class Base {
public:
Base() { std::cout << "base constructor" << std::endl; }
virtual ~Base() {}
};
class Derived : public Base {
public:
Derived() { std::cout << "derived constructor" << std::endl; }
};
int main() {
std::vector<Base> base(2);
std::cout << "----------------" << std::endl;
std::vector<Derived> derived(2);
return 0;
}
The output of the above for me is:
base constructor
----------------
base constructor
derived constructor
Why is the output not the following:
base constructor
base constructor
----------------
derived constructor
derived constructor
I'm using gcc 4.5.2 on Linux.
You're deceiving yourself: A single default construction of the derived object calls both constructors.
Now, what you are not seeing is the copy constructor, which does in fact get called twice in both cases.
The constructor of vector that you're calling makes one default construction of its value type, and then copies that into each element:
//std::vector<Derived> v(2);
std::vector<Derived> v(2, Derived()); // same thing!
This is a bit of an extension on what Kerrek wrote:
#include <iostream>
#include <vector>
class Base {
public:
Base() { std::cout << "base constructor" << std::endl; }
virtual ~Base() {
}
Base(const Base&){
std::cout << "copy base constructor" << std::endl;
}
};
class Derived : public Base {
public:
Derived() { std::cout << "derived constructor" << std::endl; }
Derived(const Derived& d):Base((const Base) d){
std::cout << "copy derived constructor" << std::endl;
}
};
int main() {
std::vector<Base> base(2);
std::cout << std::endl;
std::vector<Derived> derived(2);
return 0;
}
The output from this is:
base constructor
copy base constructor
copy base constructor
base constructor
derived constructor
copy base constructor
copy derived constructor
copy base constructor
copy derived constructor
This is the output I get from VC++ 2010:
base constructor
base constructor
base constructor
derived constructor
base constructor
derived constructor
Press any key to continue . . .
Whereas with (GCC) 4.6.1
g++ -o test test.cpp
sashan#cyclops cpp $ ./test
base constructor
base constructor
derived constructor
So it looks like it's an implementation difference....which is kinda puzzling.
Update
Compiling with c++0x gives:
sashan#cyclops cpp 1 $ g++ -std=c++0x -o test test.cpp
sashan#cyclops cpp $ ./test
base constructor
base constructor
base constructor
derived constructor
base constructor
derived constructor
Which supports Kerrek SB's comments and answer.