Suppose I have the following class:
class A{
...
B obj;
C obj2
...
}
Upon construction of an A instance, B obj would be initialized by the default constructor. But before I can construct obj and obj2, I need to do some computation in the constructor of A and then call a non-default constructor for B obj and C obj2.
It does not cost me a lot, but the call to a default constructor for B obj and C obj2 upon construction of A would be completely unnecessary.
Can I prevent C++ from calling a default constructor? Or is this the wrong approach anyways?
EDIT: For clarification, I added a second object. I have to read from a file and can then construct B and C.
It is the somewhat wrong approach. I would suggest something like this:
int arguments(){ //assuming obj takes an int as 3rd constructor argument, could be any
//do computation you wanted to do in A::A
}
class A{
A() : obj(non, Default, arguments()){}
B obj;
}
Now the initialization is done before obj is created. You may also make arguments return a B and rely on the move constructor of B.
Edit: The answer does not change much with the edited question. Now you have two objects but the same logic applies:
class A{
A() : obj(doInitCalculations()), obj2(something){}
B obj;
C obj2;
}
obj must be initialized before obj2 (even if you write A() : obj2(), obj1{}) because they are constructed in the order they are declared in the class. So doInitCalculations is still called before either object is constructed.
You may delegate your constructor, something like:
class A
{
public:
A() : A(ComputeSomethingForBAndC()) {}
private:
A(const DataToBuildBAndC& dataToBuildBAndC) :
b(dataToBuildBAndC),
c(dataToBuildBAndC)
{}
private:
B b;
C c;
};
No matter what you do, the constructor of B will be called
before you enter into the body of A. If you don't specify
anything in the initializer list, the default constructor will
be called. If you need to calculate values first, then the only
real solution would be to do so in a static member function:
class A
{
B obj;
static B initializeB( ... );
public:
A( ... ) : obj( initializeB( ... ) ) {}
};
This is fine if the calculation only depends on the arguments,
and is only needed for the initialization of B. Otherwise, it
might require doing the same calculations twice.
If the initialization of B depends on other members, which are
also calculated, then you can put the other members before obj
(so they will be initialized first), and use the static member
trick on them. (Just be sure to put a big comment to the effect
that your code absolutely depends on the order of the members.)
Finally, if nothing else works, you can arrange for a "trivial"
constructor for B, which only does the minimum so that an
assignment later will work. Then you can write:
A::A()
: obj( doNothing )
{
// all the calculation
obj = B(...);
}
(For doNothing, just use an enum:
enum DoNothing { doNothing };
The provide an overload B::B( DoNothing ) in B.)
I'd consider this a last resort, as it involves modifying B,
which is rather invasive. Still, I've used it one or two times in the past.
You could use a (smart) pointer for B.
You'll need a level of indirection, something like:
class A {
unique_ptr<B> pObj;
public:
A {
// do your pre-B stuff
pObj = std::unique_ptr<B>(new B(/* args */));
};
// other stuff
}
I would recommend, make your B class constructor private.. something like
class B
{
private:
B();
}
and no one(from outside the class itself or friend classes) will be able to call default constructor. Also, then you'll have three options for using the class: either to provide a parameterized constructor, or use it as a utility class (one with static functions only), or to create a factory for this type in a friend class.
Can I prevent C++ from calling a default constructor?
You can't if B is not an build in or an aggregate Type.
Related
I'm having a problem initializing a shared_ptr member of a class I'm working on.
I have two classes, A and B:
class A {
int _x;
int _y;
public:
A(int, int);
};
A::A(int x, int y) {
_x = x;
_y = y;
}
class B : public A {
std::shared_ptr<A> _a;
public:
B(std::shared_ptr<A>);
};
B::B(std::shared_ptr<A> a) : _a(a) {}
int main() {
std::shared_ptr<A> a = std::make_shared<A>(1, 2);
B b(a);
return 0;
}
I just want class B to hold a std::shared_ptr to an instance of class A.
However, I'm getting the error no matching function for call to A::A() in B's constructor.
I'm confused because I thought the point of the initializer list is to avoid implicitly calling the default constructor for member variables, but it still seems to be trying to call A's default constructor.
Any explanation is appreciated, thanks.
edit: after more messing around, it seems like it complies properly if B does not inherit from A. Still unsure why inheriting from A results in A's default constructor being called from B's constructor.
Since B is derived from A, every B is an A. That means to construct a B, you must also construct an A. However, you do not tell B's constructor how to construct an A, so the default constructor is used.
If you want B to be derived from A and only hold a shared_ptr to A, then A must not do anything you don't want B to do. Here, A has _x and _y.
It's not clear what you really want, but perhaps you want some other base class that both A and B derive from that only has what both A and B should have.
The classic example of inheritance in C++ is something like Instrument being the base class that has members like Play with derived classes like Trumpet and Clarinet having the thing that makes some particular instrument a trumpet. Only what is common to Trumpets and Clarinets should be in Instrument.
When you call B b(a);, you construct a B object using the constructor B::B(std::shared_ptr<A> a).
The issue is in your definition of this constructor. B inherits from A, meaning that B is not just a B, but instead is really an A and B stacked on top of each other. A is the base class, so it is on the bottom. So when you try to construct a B object, the code must first construct the A object at the bottom/base to form the foundation for the B object to exist on. That means that you actually have to tell the code how to construct the A object.
Because you defined a constructor for A that takes two int variables, the compiler does not generate a default constructor for A. Therefore, you must explicitly write out how A should be constructed within B. Constructing the A object can be done in the initializer list of the B object's constructor:
B::B(std::shared_ptr<A> a) : A(0,0), _a(a) {}
Why did the creator of C++ decide to use constructor initializer list to initialize base classes? Why didn't he instead choose to use syntax like the second comment line in the following code?
class A{
public:
A() { }
};
class B : A{
public:
B() : A() { } // Why decide to use this one, using constructor initializer, to initialize base class?
B() { A(); } // Why not choose this one? It's easy for me to understand if it was possible.
};
int main(int argc, char *argv[]){
/* do nothing */
}
The advantage of using an initializer list is, that you have a completely initialized object in the body of the constructor.
class A {
public:
A(const int val) : val(val) { }
private:
const int val;
};
class B : A{
public:
B() : A(123) {
// here A and B are already initialized
}
};
So you have a guarantee that all members, even those of the parent, are not in an undefined state.
Edit
In the example of the question it is not necessary to call the base class in the initializer list, this is done automatically. So I slightly modified the example.
I can see a few possible alternatives to the current C++ rule that base classes and data members of a class type are initialised in the mem-initialiser list of the class type's constructor(s). They all come with their set of issues, which I will discuss below.
But first, note that you cannot simply write a derived constructor like this:
struct Derived : Base
{
Derived()
{
Base(42);
}
};
and expect the line Base(42); to call the base class constructor. Everywhere else in C++, such a statement creates a temporary object of type Base initialised with 42. Changing its meaning inside a constructor (or just inside its first line?) would be a syntax nightmare.
Which means that new syntax would need to be introduced for this. In the rest of this answer, I will use a hypothetical construct __super<Base> for this.
Now on to discuss possible approaches which would be closer to your desired syntax, and present their problems.
Variant A
Base classes are initialised in the constructor body, while data members are still initialised in the mem-initialiser list. (This follows the letter of your question the closest).
The would have the immediate problem of stuff executing in different order than it's written. For very good reasons, the rule in C++ is that base class subobjects are initialised before any data members of the derived class. Imagine this use case:
struct Base
{
int m;
Base(int a) : m(a) {}
};
struct Derived
{
int x;
Derived() :
x(42)
{
__super<Base>(x);
}
};
Written like this, you could easily assume x would be initialised first and then Base would be initialised with 42. However, that would not be the case and instead reading x would be undefined.
Variant B
Mem-initialiser lists are removed altogether, base classes are initialised using __super, and data members are simply assigned in the constructor body (pretty much the way Java does it).
This cannot work in C++ because initialisation and assignment are fundamentally different concepts. There are types where the two operations do vastly different things (e.g. references), and types which are not assignable at all (e.g. std::mutex).
How would this approach deal with a situtation like this?
struct Base
{
int m;
Base(int a) : { m = a; }
};
struct Derived : Base
{
double &r;
Derived(int x, double *pd)
{
__super<Base>(x); // This one's OK
r = *pd; // PROBLEM
}
};
Consider the line marked // PROBLEM. Either it means what it normally does in C++ (in which case it assigns a double into a "random place" which the uninitialised reference r references), or we change its semantics in constructors (or just in initial parts of a constructor?) to do initialisation instead of assignment. The former gives us a buggy program while the latter introduces totally chaotic syntax and unreadable code.
Variant C
Like B above, but introduce special syntax for initialising a data member in the constructor body (like we did with __super). Something like __init_mem:
struct Base
{
int m;
Base(int a) : { __init_mem(m, a); }
};
struct Derived : Base
{
double &r;
Derived(int x, double *pd)
{
__super<Base>(x);
__init_mem(r, *pd);
}
};
Now, the question is, what have we achieved? Previously, we had the mem-initialiser list, a special syntax to initialise bases and members. It had the advantage that it made clear these things happen first, before the constructor body starts. Now, we have a special syntax to initialise bases and members, and we need to force the programmer to put it at the start of the constructor.
Note that Java can get away with not having a mem-initialiser list for several reasons which don't apply to C++:
The syntax for creating an object is always new Type(args) in Java, whereas Type(args) can be used in C++ to construct objects by value.
Java only uses pointers, where initialisation and assignment are equivalent. For many C++ types, there operations are distinct.
Java classes can only have one base class, so using just super is enough. C++ would need to differentiate which base class you're referring to.
B() : A() { }
This will initialize the base class in user defined way.
B() { A(); }
This will NOT initialize the base class in user defined way.
This will create an object inside of constructor i.e B(){}
I think first initialization has better readability compared to the second and you can also deduce class hierarchy.
Basically, I have one class that owns another object:
class A()
{
A() { initSystems() };
void initSystems();
B b;
}
class B()
{
B() { //Does stuff that requires 'initSystems()' to be called before }
}
and for 'B' to function, the init systems function needs to be called in A. Is there any 'nice' way to work around this? Like creating the 'B' object later or something?
Sounds like your classes are too tightly coupled. There's many ways to fix this, but it depends on the rest of your design.
Maybe A shouldn't own a B, since A is a dependency of B. You could inject an instance of A into each B as they get instantiated.
Maybe B shouldn't exist and all, and it should be merged into A:
class A()
{
A() {
initSystems();
//Does stuff that requires 'initSystems()' to be called before
}
void initSystems();
// B's methods
}
It's my opinion that most initialization methods are code smells (that is, it suggests a bad design). Some people have given this pattern a name: "Design Smell: Temporal Coupling"
If you desire to keep the B a regular member of A, the two places you can run code before the construction of b are:
the constructor of a base class of A,
in the initializer list of a member of A, for a member declared above b.
If you wish to defer construction of the B, you need to hold the object by indirection or later construct it onto raw storage and when destroying, perform placement destruction.
Most of this has strange smells to it, it may be beneficial to reorganize your code to avoid this kind of structure.
You simply need to change your design so initSystems() is requirement for both A and B.
If you can't do this (although you really should), there are other ways, like dynamic allocation:
class A()
{
A() {
initSystems();
b = std::make_unique<B>();
};
void initSystems();
std::unique_ptr<B> b;
}
I agree with #nanny over the decoupling of the class and merging if possible.
But your scenario seems like in which B is separate entity in your system, hence a class. And A contains a B, hence the composition.
So one way of solving this would be, you keep a reference (pointer) to B in A instead of making B a part of A.
Or you should not access the stuff that is created in initInstance() of A in the constructor of B, and create a method postConstruct in B that you can call from A after call initInstance. Following code explains it,
class A()
{
A()
{
initSystems();
b.postContruct()
}
void initSystems()
{
// do the init instance stuff here.
}
B b;
}
class B()
{
B() {}
void postContruct()
{
//Does stuff that requires 'initSystems()' to be called before
}
}
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 ?
Constructors are meant to create objects. Hence they are used once. You should create a method to do initialization and call that from constructors.
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.
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.
init method
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.
Wrapper
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.
The error
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.
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.
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.
I have two classes A and B, and in class A I have an member of type B:
class B {
public:
B(); //default constructor
};
class A {
public:
A(); //constructor
B b;
};
This is the definition of class A's constructor:
A::A() : b()
{}
Here, I tried to initialize b using the initialization list. My question is, is this way to initialize b correct, or am I just creating another temporary object named b inside the constructor of A that has nothing to do with A::b?
This is correct. However, since b is of class type, the default constructor will be called automatically if b isn't mentioned in A::A's initialization list, so you don't need to mention it at all.
This method will initialize the field b with the constructor B::B(). It does not create a temporary local.
Note that in this particular case it's also unnecessary. The default constructor generated for A will do this by itself. There is nothing wrong with being explicit here, it's just unnecessary