Reputation: 139
I have two classes A
and B
. bclass
of type B
is a constant member of class A
; what I want to do is to initialize class bclass
with default values if no B
object is provided to A
.
Something like this:
#include <iostream>
#include <string>
#include <unistd.h>
using namespace std;
class B{
public:
B(string Bs): Bstring(Bs){
cout << "B constructor: " << Bstring << endl;
}
~B(){
cout << "B destructor: " << Bstring << endl;
}
private:
const string Bstring;
};
class A{
public:
A(const B subb = B("mmmmm")): bclass(subb){
cout << "A constructor." << endl;
}
~A(){
cout << "A destructor." << endl;
}
private:
const B bclass;
};
int main(void){
A a;
cout << "doing work..." << endl;
sleep(2);
return 0;
}
The output is:
B constructor: mmmmm
A constructor.
B destructor: mmmmm
doing work...
A destructor.
B destructor: mmmmm
The thing is that I'm constructing 2 B classes(?) when only one is needed! And somehow, B constructor is called only once, while the destructor is called twice... What is going on?!
EDIT 1:
After reading the (great) response of @WhiZTiM, I added the next two updates...
The next code explains when the second constructor is called:
#include <iostream>
#include <string>
#include <unistd.h>
using namespace std;
class B{
public:
B(string Bs): Bstring(Bs){
cout << "B constructor: " << Bstring << endl;
}
B(const B& bobj): Bstring(bobj.Bstring + "(copy)"){
cout << "B copy constructor: " << Bstring << endl;
}
~B(){
cout << "B destructor: " << Bstring << endl;
}
private:
const string Bstring;
};
class A{
public:
A(const B& subb = B("mmmmm")): bobj(subb){
cout << "A constructor." << endl;
}
~A(){
cout << "A destructor." << endl;
}
private:
const B bobj;
};
int main(void){
A a;
cout << "doing work..." << endl;
sleep(2);
return 0;
}
output:
B constructor: mmmmm
B copy constructor: mmmmm(copy)
A constructor.
B destructor: mmmmm
doing work...
A destructor.
B destructor: mmmmm(copy)
As @WhiZTiM pointed to me, the compiler elided a third call to the B constructor (Thanks!).
EDIT 2: As I want only 1 B object, the best idea is to use pointers. The code must be:
#include <iostream>
#include <string>
#include <unistd.h>
using namespace std;
class B{
public:
B(const string Bs): Bstring(Bs){
cout << "B constructor: " << Bstring << endl;
}
B(const B& bobj): Bstring(bobj.Bstring){
cout << "copying an existing B object." << endl;
}
~B(){
cout << "B destructor: " << Bstring << endl;
}
private:
const string Bstring;
};
class A{
public:
A(B* subb = new B("mmmmm")): objb(subb){
cout << "A constructor." << endl;
}
~A(){
cout << "A destructor." << endl;
delete objb;
}
private:
const B* const objb;
};
int main(void){
A a1; // This will call the default B constructor.
A a2(new B("ooooo"));// This is calling a non default B object constructor.
cout << "doing work..." << endl;
sleep(2); //I need more motivation...
return 0;
}
This is the output:
B constructor: mmmmm
A constructor.
B constructor: ooooo
A constructor.
doing work...
A destructor.
B destructor: ooooo
A destructor.
B destructor: mmmmm
Thanks a lot to @WhiZTiM
Upvotes: 1
Views: 346
Reputation: 21576
The thing is that I'm constructing 2 B classes(?) when only one is needed! And somehow, B constructor is called only once, while the destructor is called twice... What is going on?!
There is no magic going on. The compiler generated implicit copy and move constructors. To get the true picture, implement yours
class A{
public:
A(const B subb = B("mmmmm")): bclass(subb){
cout << "A constructor." << endl;
}
~A(){
cout << "A destructor." << endl;
}
private:
const B bclass;
};
In your constructor, B
is created using your single argument constructor, then assigned to subb
, it is then copied to bclass
... So there were actually 3 instances of B
created.
subb
- compiler generated defaultbclass
- compiler generated defaultYou may have seen 2 because, the compiler elided a call
Upvotes: 1