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.
Related
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).
Why aren't copy constructors chained (like default ctors or dtors) so that before the derived class's copy constructor is called, the base class's copy constructor is called? With default constructors and destructors, they are called in a chain from base-to-derived and derived-to-base, respectively. Why isn't this the case for copy constructors? For example, this code:
class Base {
public:
Base() : basedata(rand()) { }
Base(const Base& src) : basedata(src.basedata) {
cout << "Base::Base(const Base&)" << endl;
}
void printdata() {
cout << basedata << endl;
}
private:
int basedata;
};
class Derived : public Base {
public:
Derived() { }
Derived(const Derived& d) {
cout << "Derived::Derived(const Derived&)" << endl;
}
};
srand(time(0));
Derived d1; // basedata is initialised to rand() thanks to Base::Base()
d1.printdata(); // prints the random number
Derived d2 = d1; // basedata is initialised to rand() again from Base::Base()
// Derived::Derived(const Derived&) is called but not
// Base::Base(const Base&)
d2.printdata(); // prints a different random number
The copy constructor doesn't (can't) really make a copy of the object because Derived::Derived(const Derived&) can't access basedata to change it.
Is there something fundamental I'm missing about copy constructors so that my mental model is incorrect, or is there some arcane (or not arcane) reason for this design?
The copy constructor doesn't (can't) really make a copy of the object because Derived::Derived(const Derived&) can't access pdata to change it.
Sure it can:
Derived(const Derived& d)
: Base(d)
{
cout << "Derived::Derived(const B&)" << endl;
}
If you don't specify a base class constructor in the initializer list, its default constructor is called. If you want a constructor other than the default constructor to be called, you must specify which constructor (and with which arguments) you want to call.
As for why this is the case: why should a copy constructor be any different from any other constructor? As an example of a practical problem:
struct Base
{
Base() { }
Base(Base volatile&) { } // (1)
Base(Base const&) { } // (2)
};
struct Derived : Base
{
Derived(Derived&) { }
};
Which of the Base copy constructors would you expect the Derived copy constructor to call?
You can:
Derived(const Derived& d) : Base(d) {
cout << "Derived::Derived(const B&)" << endl;
}
This calls the Base copy constructor on the Base sub-object of d.
The answer for 'why' I don't know. But usually there's no answer. The committee just had to choose one option or the other. This seems more consistent with the rest of the language, where e.g. Derived(int x) won't automatically call Base(x).
That's because every constructor calls by default the default base constructor:
Derived(const Derived& d) {
cout << "Derived::Derived(const B&)" << endl;
}
will call Base().
This is defined by the standard. I for one prefer it like this rather than calling the copy constructor on the class. You can of course call it explicitly.
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.
Im receiving error C2082: redefinition of formal parameter 'rval' in this code while trying to call base copy ctor explicitly:
#include <iostream>
using namespace std;
class Base
{
public:
Base(const Base& rhs){ cout << "base copy ctor" << endl; }
};
class Derived : public Base
{
public:
Derived(const Derived& rval) { Base(rval) ; cout << "derived copy ctor" << endl; }
// error C2082: redefinition of formal parameter 'rval'
};
int main()
{
Derived a;
Derived y = a; // invoke copy ctor
cin.ignore();
return 0;
}
However if do it like this:
Derived(const Derived& rval) { Base::Base(rval) ; cout << "derived copy ctor" << endl; }
then is OK.
Why am I asking this?
according to the answers on StackOwerflow
I do not have to use operator :: to access base copy ctor,
so why do I receive this error?
btw: I'm using visual studio 2010.
I'm having one more question:
Do I have to call base's move constructor in user defined move constructor of derived class?
To call the base constructor you need to put the call in the member initalization list
class Derived : public Base
{
public:
Derived(const Derived& rval) : Base(rval)
{
cout << "derived copy ctor" << endl;
}
};
Assuming that you mean 'move' constructor is the copy constructor - Yes. You will have to call the Base's constructor. Otherwise the definition if the base object within the derived object will not be complete. You can either call a copy constructor or a normal constructor of the base class.
Why aren't copy constructors chained (like default ctors or dtors) so that before the derived class's copy constructor is called, the base class's copy constructor is called? With default constructors and destructors, they are called in a chain from base-to-derived and derived-to-base, respectively. Why isn't this the case for copy constructors? For example, this code:
class Base {
public:
Base() : basedata(rand()) { }
Base(const Base& src) : basedata(src.basedata) {
cout << "Base::Base(const Base&)" << endl;
}
void printdata() {
cout << basedata << endl;
}
private:
int basedata;
};
class Derived : public Base {
public:
Derived() { }
Derived(const Derived& d) {
cout << "Derived::Derived(const Derived&)" << endl;
}
};
srand(time(0));
Derived d1; // basedata is initialised to rand() thanks to Base::Base()
d1.printdata(); // prints the random number
Derived d2 = d1; // basedata is initialised to rand() again from Base::Base()
// Derived::Derived(const Derived&) is called but not
// Base::Base(const Base&)
d2.printdata(); // prints a different random number
The copy constructor doesn't (can't) really make a copy of the object because Derived::Derived(const Derived&) can't access basedata to change it.
Is there something fundamental I'm missing about copy constructors so that my mental model is incorrect, or is there some arcane (or not arcane) reason for this design?
The copy constructor doesn't (can't) really make a copy of the object because Derived::Derived(const Derived&) can't access pdata to change it.
Sure it can:
Derived(const Derived& d)
: Base(d)
{
cout << "Derived::Derived(const B&)" << endl;
}
If you don't specify a base class constructor in the initializer list, its default constructor is called. If you want a constructor other than the default constructor to be called, you must specify which constructor (and with which arguments) you want to call.
As for why this is the case: why should a copy constructor be any different from any other constructor? As an example of a practical problem:
struct Base
{
Base() { }
Base(Base volatile&) { } // (1)
Base(Base const&) { } // (2)
};
struct Derived : Base
{
Derived(Derived&) { }
};
Which of the Base copy constructors would you expect the Derived copy constructor to call?
You can:
Derived(const Derived& d) : Base(d) {
cout << "Derived::Derived(const B&)" << endl;
}
This calls the Base copy constructor on the Base sub-object of d.
The answer for 'why' I don't know. But usually there's no answer. The committee just had to choose one option or the other. This seems more consistent with the rest of the language, where e.g. Derived(int x) won't automatically call Base(x).
That's because every constructor calls by default the default base constructor:
Derived(const Derived& d) {
cout << "Derived::Derived(const B&)" << endl;
}
will call Base().
This is defined by the standard. I for one prefer it like this rather than calling the copy constructor on the class. You can of course call it explicitly.