Reputation: 2668
I have derived class and base class. in the constructor of the derived class I have to use the basic constructor of the base class. Then later on I want to re-construct the base class with deiffernet base class constructor :
class A
{
public:
int a, b;
}
class B : public A
{
B() : A()
{
...
//do some calculations to calculate a and b and then
//re-construct class A with the right values.
A(a,b) <--- ????
}
}
how to I do that ?
Upvotes: 1
Views: 1847
Reputation: 22267
As others already pointed out, you can only call inhereted constructors in the initialization list of your current constructor, or (in C++11) delegate to other constructors of your current class. This is the only place where you can initialize your class.
In some cases it makes sense to add in init()
method, which re-initializes parts of your class. This is called two-phase-initialization. You will find it in some window-managing-APIs.
It is important to note that your object is then separated into two parts: The one that is usefully initialized in the c'tor, and the other that is initialized in init()
. You must (must, must must!) initialize both parts in a way that the object is in a consistent state -- in must never be in an invalid state. As a rule of thumb: If the object is created (by a c'tor), then a destructor call must always possible. Specificly: Don't leave any pointers and handles lying around with random values.
class ChildWindow : Compontent {
shared_ptr<Component> parent_; // builds the component hierarchy
Component[] children_; // child cp'nts, unknown during c'tor
size_t nchildren_; // ...use e vector in real code!
public:
ChildWindow(chared_ptr<>Component> parent)
: parent_(parent),
children(nullptr), nchildren(0) // MUST initialize
{}
void addChild(Component *child) { /*... change children_ ...*/ }
void init() {
if(nchildren > 0) { /* ...throw away old ... */ }
children_ = new Component[...];
// ... init children_ with nulls
}
};
This is only a rough idea where you may use two-phase initialization.
If you really just need to re-initialize everything, a technical solution might to use a simple wrapper class around you real object:
class WindowWrapper {
Window *window_;
public:
WindowWrapper() : window_(nullptr) {}
void reset() { delete window_; window_ = nullptr; }
Window& get() { return *window_; }
Window& operator*() { return get(); }
}
...typed down off-hand, probably some errors in it. This is why there already is such a wrapper in C++11:
unique_ptr<Window> win { new Window{parent, "title"} };
// ..use win...
win.reset( new Window{otherparent, "other title"} };
And if this unique_ptr
is not enough you could put this inside the above wrapper.
Just as a side note, To explain what the code you wrote does:
B::B() : A() {
A(a,b); // <--- ????
}
When you type line "????", you create a *temporary object of type A
, which disappears on function exit. It does not call any destructor on your current object.
Why does it create a temp object? Well, you can write
A a(a,b);
as a statement and you get a new instance a
of class A
, constructed with the a c'tor with two arguments. This a
you could use in another function call, say func(a);
. But you can spare that explicit variable a
by just leaving out its name:
func(A(a,b));
calls func
with an unnamed ("temporary") object of class A
, which disappears at the end of the statement (i.e. ;
).
And these kind of temp objects you can create as an expression. And since every expression is also a statement
A(a,b);
is a valid statement -- creating a temp object, which immediately vanishes.
Upvotes: 2
Reputation: 9406
Put the code to compute a and b into a method and use it in the initializer list:
class A {
public:
A(int a, int b): a_(a), b_(b) {}
};
class B : public A
{
public:
B(): A(B::computeA(), B::computeB()) {}
private:
static int computeA();
static int computeB();
};
I have made the methods static to prevent using a partially initialized object.
Although I have to say that the question and the example sound like you are using inheritance to re-use an implementation. In this case, you should not use inheritance but composition and replace the inheritance with a member object.
Upvotes: 0
Reputation: 3343
You cannot call the constructor of your superclass except in your initializer list. You have to use composition instead of inheritance if you want to use operations on a differrently constructed A object. If a method changes an already constructed object, it is not a contructor. So either replace the object with a newly constructed one (instead of changing it) or use non constructor methods.
Upvotes: 0
Reputation: 17708
You could provide a copy and/or move assignment operations in class A
.
class A
{
public:
int a, b;
// Copy assignment operator
A& operator=(const A& rhs) {
if(this == &rhs) return *this;
a = rhs.a; b = rhs.b;
return *this;
}
// ...
};
After the above you could reinitialize it using the pattern
BaseClass::operator=(BaseClass(a,b));
which, in your case is
A::operator=(A(a,b));
If your class is an aggregate, or has an implicitly defined copy constructor, you should use those (you don't have to define your own), and use the same reinitialization pattern as above.
Upvotes: 2
Reputation: 11256
Constructors are meant to create objects. Hence they are used once. You should create a method to do initialization and call that from constructors.
Upvotes: 6