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
Related
I am learning about inheritance right now, and there is one thing I haven't found a solid answer on. If I have three classes one being a super and two subclass, would my subclasses need a default constructor if they inherit the same fields? Class b doesn't have a default constructor because it inherits its fields from A, where as class c has different fields, therefore it would need its own default constructor.
class A {
private:
int a;
int b;
public:
A();
A(int, int);
};
class B: public A {
public:
B(int, int);
};
class C : public A {
private:
int c;
public:
C();
C(int, int);
};
anything is greatly appreciated.
If [irrelevant], would my subclasses need a default constructor if [irrelevant]?
That depends on how your subclasses are used. If – and only if – you need to construct an instance of your class without providing construction parameters, then that class needs a default constructor. Whether or not you need to explicitly define (or forward via using) a default constructor depends on whether or not other constructors are defined, and on whether or not that constructor has something non-trivial to do. This topic should have been covered long before inheritance.
There is, however, a new caveat when inheritance enters the picture. Since I cannot tell if you use member initialization lists, I recommend reading No Matching Function Call to Base class. If you do not use member initialization lists, your derived classes will construct their bases without construction parameters. However, note that it is usually better to address this situation by using initialization lists rather than adding a default constructor.
Class b doesn't have a default constructor because it inherits its fields from A,
No, class B doesn't have a default constructor because it defines a non-default constructor. The non-default constructor prevents the compiler from supplying a default constructor. If your code successfully compiles, one can conclude that B does not need a default constructor.
where as class c has different fields, therefore it would need its own default constructor.
Whether or not a class has fields is irrelevant to "need". (Fields may make it more likely that an explicit default constructor is appropriate since there might be data to initialize, but their mere existence does not dictate a need.)
A class should have a default constructor if you intend for calling code to be able to use a default constructor and create an instance of the class without passing additional arguments to it. B won't automatically get A's default constructor just because B adds no additional member variables.
B won't automatically have a default constructor just because A has one and B doesn't have any new variables. If you want to forward A's default constructor, you can do so with a using declaration like so:
class A {
private:
int a;
int b;
public:
A();
A(int, int);
};
class B: public A {
public:
using A::A; // All of A's constructors are now publically usable as B constructors
};
Note that I removed the declaration B(int, int); because the using declaration brings both constructors forward from A. If you want B(int, int); to do something different than A(int, int);, you can declare B(int, int); alongside the using declaration and the more derived constructor will shadow the inherited constructor.
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) {}
I have 2 classes Class A and B. I am trying to use Class B's default constructor to call class A's default constructor to intialize the values of class A in class B.
class A
{
A();
int x;
}
A::A()
{
//initialized x
x=10;
}
class B
{
B();
A aobj;
}
B::B()
{
//Calling class A's default constructor to initialize B's aobj.
aobj();
}
I received a no match call to '(aobj)'. Please help me to resolve.
Actually, you don't need to explicitly default construct members as that happens automatically unless you explicitly construct the member otherwise. In case you want to really construct a member explicitly, whether it is default construction or something else, you'll need to put your initialization into the member initializer list:
B::B()
: aobj() {
}
The expression aobj() in the body of a function tries to use the function call operator on the member aobj. Doing so may be reasonable, e.g., when aobj is of type std::function<void()>.
In the context of a statement, aobj() does not try to construct the aobj variable, rather it attempts to call it using the operator() operator overload.
Instead, try doing the construction in B::B()'s initializer list:
B::B() : aobj()
{
}
But note that this is redundant, since the default constructor for member objects will be called implicitly if omitted from the initializer list. That is, this constructor would do the exact same thing:
B::B() { }
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.
I've known that if B is derived from A, then when I create a new object of B, for example b, the constructor of A will call first. When I destroy the object b, The destructor of B will call first. Then I have a question here, if there're more than one constructor in the Base class, which constructor will call ? and why?
I've write one test program below, I guess it will call the default constructor in the Base class, But I'm not sure if it is just a coincidence?
#include <iostream>
using namespace std;
class A{
public:
A(int i){cout<<"A con with param"<<endl;}
A(){cout<<"A con"<<endl;}
~A(){}
};
class B : public A
{
public:
B(int i){cout<<"B con with param"<<endl;}
B(){cout<<"B con"<<endl;}
~B(){}
};
int main()
{
B b(5);
return 0;
}
I wonder if any boss can tell me the reason or any advise to figure out this problem?
If you write:
B(int i) { cout<<"B con with param"<<endl; }
then constructor A() (without arguments) will be called.
If you write:
B(int i): A(i) { cout<<"B con with param"<<endl; }
then constructor A(int) will be called.
Nothing is by coincidence in programming.
The default constructor is called because, you did not pass int argument explicitly to base class.
For other constructor of base class to be called, the derived class constructor needs to pass the parameters to base class constructor.
So for A(int) to be called, you need to have B():A(some_int) or B(int):A(some_int)
The empty constructor of the parent class will be called unless you call some other constructor explicitly in the initializer list.
EDIT: here is how you call constructor explicitly:
B(int i) : A(i) {
... do stuff ...
}
The order of initialization is a bit more convoluted than that. Technically it starts in the initialization list of the most derived object. That constructor is selected with regular overload resolution from the location where the object is being created. The initialization list of the most derived type constructor lists (either explicitly or implicitly) the constructors of the bases, and again the constructor of the bases will be selected using overload resolution on the call in the initialization list. If the base is not explicitly stated in the initialization list, the compiler will inject a call to the default constructor.
The exact order of construction is also a bit more complex in that the first subobjects that are initialized are the virtual bases, in a particular order (depth-first, left-to-right where left-to-right is the order of declaration in the base classes declaration). Once all virtual bases are initialized, then the direct non-virtual bases of the most derived type are initialized, again in the order of declaration (left-to-right). Once all bases are initialized, the members are then initialized in the order of declaration in the class.
Note that in all cases, the code can explicitly list the subobject in the initialization list, and the constructor listed there will be used, or the default constructor if the entity is not listed.