I know this as this will assign the constructor parameter to the class member:
class A
{
public:
some_type B;
A(some_type B)
{
this->B = B;
}
}
But what will this do:
class A
{
public:
some_type B;
A(some_type B) : B(B)
{
}
}
Will this assign the parameter to itself or the parameter to the class member or do something else?
How are the names in the list after construct thing (I have no idea how its called) resolved?
That Thing is called a Member Initializer List in C++.
There is a difference between Initializing a member using initializer list(2nd Example) and assigning it an value inside the constructor body(1st Example).
When you initialize fields via initializer list the constructors will be called once. The object gets constructed with the passed parameters.
If you use the assignment then the fields will be first initialized with default constructors and then reassigned (via assignment operator) with actual values.
As you see there is an additional overhead of creation & assignment in the latter, which might be considerable for user defined classes.
How are the names in the list after construct thing (I have no idea how its called) resolved?
public:
some_type B;
A(some_type B) : B(B)
{
}
In the above snipet, there are two entities named B:
First is the one that constructor receives as an argument &
Second is the member of the class A
The variable received as argument in Constructor of A gets passed as an argument for constructing B(by calling its constructor) which is member of class A. There is no ambiguity in names here, the all to constructor is:
this->B(B);
this is class A pointer.
B() is constructor of type B.
B inside the parenthesis is an instance of type B.
Will this assign the parameter to itself or the parameter to the class
member or do something else?
It will assign the parameter to the class member.
How are the names in the list after construct thing (I have no idea
how its called) resolved?
This is the initializers list, and though the example can lead to confusion, the id at the left of the parenthesis is a member of the class, while the id (or literal) inside the parenthesis can only be one of the parameters of the constructor: thought that way, there is no ambiguity at all.
The key here is that this list must initialize class members with some value, so if you think of
...: B(B)
as conceptually equivalent to a constructor call:
this->B(B)
... there is no ambiguity.
In the first situation, your objet will be constructed. In the second, it will be constructed (with default constructor) and assigned.
You might not want assignation (maybe the operator is not defined, or no default constructur or the behaviour is specific, or maybe, in some cases because of performance issues).
Concerning the visibility, in both cases, if you just use B, it's the parameter you're manipulating.
Related
I wrote a class that holds an array of objects, which each expect a pointer to a c-struct in their constructor:
Here's some code:
class TheOtherClass
{
private:
SomeCStruct* m_pCStruct;
int m_ObjIdx;
public:
TheOtherClass::TheOtherClass(SomeCStruct* pCStruct, int ClassIdx)
: m_pCStruct(pCStruct),
m_ObjIdx(ClassIdx)
{}
}
class MyClass
{
private:
TheOtherClass m_objects[4];
SomeCStruct* m_pMyCStruct;
public:
MyClass::MyClass(SomeCStruct* pCStruct)
: m_pMyCStruct(pCStruct)
{
m_objects[4] = {TheOtherClass(&pCStruct, 1), TheOtherClass(&pCStruct, 2),
TheOtherClass(&pCStruct,3), TheOtherClass(&pCStruct, 4)};
}
I'd actually like to initialize the member objects of MyClass in the init list of the constructor but I was reading this isn't possible?
Hence I tried the above approach but I'm always getting the error: "TheOtherClass": no appropriate default constructor available.
Another thing to mention is that the compiler I'm running is a state of the art C++03 compiler ;-) (it's code for a DSP and TI sort of doesn't wants to update the compiler)
Any help would be highly appreciated!
Since MyClass(SomeCStruct* pCStruct) constructor doesn't (can't) initialize the TheOtherClass m_objects in the member initializer list, the m_objects will need to be default constructed at first, and then this member will be reassigned with new value in the body of the MyClass constructor.
The TheOtherClass won't have a synthesized constructor since you have defined (other, non-default) ctor that takes SomeCStruct* and int. Thus, no default constructor for it in your code.
Here, we define a default constructor:
class TheOtherClass {
SomeCStruct* m_pCStruct;
int m_ObjIdx;
public:
TheOtherClass() : m_pCStruct(nullptr), m_ObjIdx(0) {} // Default ctor
TheOtherClass(SomeCStruct* pCStruct, int ClassIdx)
: m_pCStruct(pCStruct),
m_ObjIdx(ClassIdx) {}
};
As to the MyClass. Since you've already pass the argument as a pointer MyClass(SomeCStruct* pCStruct), you don't need to take the address of it (as in &pCStruct).
And the main issue in the MyClass is that the m_objects is of class type TheOtherClass which does not define any operator=, including the one that takes brace-enclosed initializer list. So, you won't be able to do like so:
m_objects[4] = { // The operator '=' has not been defined for the TheOtherClass, also note the subscript
TheOtherClass(pCStruct, 1),
TheOtherClass(pCStruct, 2),
TheOtherClass(pCStruct,3),
TheOtherClass(pCStruct, 4)
};
Again, when you try to list initialize it, it has already been default constructed. Thus, for this approach to work you will need to define such copy-assignment operator to do this kind of assignment to an already default constructed instance of the TheOtherClass. As to how to implement this operator, it will mostly depend on the overall design and other factors which were not mentioned in this thread.
Update
If you will have the following body of the MyClass constructor, it will work:
MyClass(SomeCStruct* pCStruct) : m_pMyCStruct(pCStruct) {
// Assign to default initialized TheOtherClass object
m_objects[0] = TheOtherClass(pCStruct, 1);
}
I would advise you to check these:
Operator overloading
Constructors and member initializer lists
I apologize in advance because some of my verbiage may not be 100% correct.
I will have a class like this:
class ClassName {
private:
AnotherClass class2;
public:
ClassName();
~ClassName();
...
In the constructor of this class, among other things, I put the line
ClassName::ClassName() {
AnotherClass class2;
}
Which is how I thought you were supposed to initialize objects in C++, however I was noticing (through GDB) that two AnotherClass objects were being created. Once on the Constructor definition then again on my initialization line. What is the reasoning behind this? What if I wanted to use a more complicated constructor like AnotherClass(int a, int b), would it create a temporary object then create the correct one shortly after?
AnotherClass class2; creates another local object inside the constructor body, that gets destroyed at the end of the body. That is not how class members are initialized.
Class members are initialized before the constructor body in the member initializer list between the constructor signature and body, starting with a :, like so:
ClassName::ClassName() :
class2(argumentsToPassToClass2Constructor),
anotherMember(42) // just for example
{
/* constructor body, usually empty */
}
If you don't want to pass any arguments to the class2 constructor you don't have to put it in the initializer list. Then its default constructor will be called.
If you simply want to call the default constructor on all of your class members, you can (and should) omit the constructor altogether. The implicitly generated default constructor will do just what you wanted.
What you are doing in your constructor is creating another variable, local only inside the constructor.
Actually, if you do nothing, the default constructor in AnotherClass will be called for the class2 object.
If you want to be explicit, you can use a constructor initializer list:
ClassName::ClassName()
: class2()
{
}
This last method is also the way you call a specific constructor with arguments in AnotherClass, if you need to do that.
ClassName::ClassName() {
AnotherClass class2; // this will create local variable only
}
If AnotherClass will have default constructor, then it will be called for the class2 object by compiler.
If you want to call parametrized constructor then you will have do it in following way:
ClassName::ClassName() :
class2(arguments)
Why to use and How to use initializer list :
Consider the following example:
// Without Initializer List
class MyClass {
Type variable;
public:
MyClass(Type a) { // Assume that Type is an already
// declared class and it has appropriate
// constructors and operators
variable = a;
}
};
Here compiler follows following steps to create an object of type MyClass
Type’s constructor is called first for “a”.
The assignment operator of “Type” is called inside body of MyClass() constructor to assign
variable = a;
And then finally destructor of “Type” is called for “a” since it goes out of scope.
Now consider the same code with MyClass() constructor with Initializer List
// With Initializer List
class MyClass {
Type variable;
public:
MyClass(Type a):variable(a) { // Assume that Type is an already
// declared class and it has appropriate
// constructors and operators
}
};
With the Initializer List, following steps are followed by compiler:
Copy constructor of “Type” class is called to initialize : variable(a). The arguments in initializer list are used to copy construct “variable” directly.
Destructor of “Type” is called for “a” since it goes out of scope.
As we can see from this example if we use assignment inside constructor body there are three function calls: constructor + destructor + one addition assignment operator call. And if we use Initializer List there are only two function calls: copy constructor + destructor call.
This assignment penalty will be much more in “real” applications where there will be many such variables.
Few more scenarios, where you will have to use initializer list only:
Parametrized constructor of base class can only be called using Initializer List.
For initialization of reference members
For initialization of non-static const data members
You are just creating a local variable in this line. In general there are three ways of initializing private members:
Default initialization
If you do nothing on your constructor, the compiler will automatically initialize the private member by calling its default constructor (ctr without parameters)
Assigning them to a value in the ctr body
In this case you have to assign the desired value to your private member by using the assignment operator.
ClassName::ClassName()
{
class2 = AnotherClass(a, b, c); // if the class ctr has some parameters
}
By using the initialization list
In your case it will be something like:
ClassName::ClassName()
: class2(initial_value)
{
}
This is in general the best and efficient option for initializing your class private members since you avoid calling the copy constructor for the passed parameters. This is in general is not an issue unless the copy ctr contains time-consuming operations. The same apply for the option #2 in this case you may have the same issues with the assignment operator
What you did there is to create a new variable with the same name as you member,
By doing this you overshadowed your member variable.
Also, in the process your member constructor was silently called in the ClassName empty initialisation list.
you can initiate the class in two ways:
ClassName::ClassName(): class2() {}
or:
ClassName::ClassName() {
this->class2 = AnotherClass();
}
The first way is better and a must some times.
If you only use empty constructors for your members you won't see the difference, except in performance, because the compiler initialize the member by default in its initialisation list ( the part after the ":", if you don't do that, he does it silently for you... )
But if your member doesn't have an empty constructor, for example:
AnotherClass:: AnotherClass(int a, int b)
if you will try to use the second way on initialisation you will get a message like:
error: constructor for 'Initiator' must explicitly initialize the member 'class2' which does not have a default constructor
I came across this question which asks its output.
#include<iostream>
using namespace std;
class A{
public:
int i;
A(int j=3):i(j){}
};
class B:virtual public A{
public:
B(int j=2):A(j){}
};
class C:virtual public A{
public:
C(int j=1):A(j){}
};
class D:public B, public C {
public:
D(int j=0):A(j), B(j+1), C(j+2){}
};
int main()
{
D d;
cout<<d.i;
return 0;
}
There are few things which I did not understand.
Please clarify these doubts.I could not google it as I did not know what to search for.
Q1. As in the code a parameterised constructor is used.Just after the colon(:) we write the constructor of the parent class.How
A(int j=3):i(j){}
is used? As i is not a class.
Q2. In the class D, the constructor for the class is using the constructors for initialising the base classes.But as it can be seen that all the constructors modify variable i of the class A only.
Then what is the sequence of the constructor calling here.
I know when we do not call the constructor of the parent class, it is explicitly called and the order is well known, but what when we implicitly call the constructor like here.
Q3. Inspite of the parameters being initialized, the value which we send in the constructor seems to make a difference.Why is it so ?
A1. :i(j) in A(int j=3):i(j){} is an initializer list. Initializer lists can specify how parent classes and member variables are initialized. (j) is the initializer for i and behaves similarly to initialization for a local variable: int i(j);. (you may be more familiar with the initialization syntax int i = j; which is similar. You can't use the = syntax in initializer lists.)
A2. Virtual base classes are always initialized exclusively by the most derived class's constructor. So D's constructor initializes its A base class and when D's constructor calls the constructors for B and C those constructors do not reinitialize A.
A3. The syntax D(int j=0) does not initialize the parameter. Instead it declares a default value for the parameter which is ignored whenever you explicitly pass a value for that parameter.
The ctor-initializer-list contains the initializers for all subobjects. That means base class subobjects and member subobjects.
Subobjects are initialized in the order in which they appear in the class definition, always. it doesn't matter what order you put them in the ctor-initializer-list (although putting them in any other order is confusing when the order is ignored).
Inherited base subobject constructors are called by the constructor of the class which is directly derived... except for virtual base subobjects, which are called directly from the constructor for the most-derived object. Virtual base subobjects are constructed before anything else.
There's no such thing as "parameters being initialized". Those are default arguments, and they are ignored when an actual argument is provided.
1) The colon : can be used in a constructor to call the constructors of member variables with the given arguments:
public:
int i;
A(int j=3):i(j){}
means that A's member i will call its constructor with j as the argument.
2) Subobjects will be initialized in the order they appear in the class definition
class D:public B, public C
3) They weren't initialized, they were given default arguments.
Q1:
That code in the constructor between the signature of the function and before the opening bracket of the function body is called an initializer list.
The syntax of an initializer list is a listing of member variables of the class with corresponding initial values. The initial values are in parenthesis. The member variables are separate by comma's. The first variable comes after a colon.
An initializer list can also include a constructor to base class, which is what your B and C class do. Your 'A' class simply uses the form that initializes a member variable.
Q2:
To find the order that the constructors are executed in, put in some print statements. It will help you understand the order of construction. Also put in a destructor and put print statements in those too. I can't do all of your homework for you on this question. :)
Q3:
I guess by parameters being initialized you mean the default arguments? Default arguments are always always overridden if a value is actually passed into the function.
So I have searched all over the place and I can not seem to find the answer to this specific question. I am using a winXP with cygwin and gcc 3.4.4 cygming special.
Problem:
I have a class that works as an interface with some abstract methods and protected variables that should be in every class that inherits from this class. Now I also have another class that is a member variable of this interface.
class Bar {
private:
int y;
public:
Bar(int why);
};
Bar::Bar(int why) : y(why) {}
class Foo {
protected:
Bar b;
public:
Foo(int x);
virtual void print_base();
};
Foo::Foo(int x) : b(x+3) // Have to use initializer list here.
{
//this->b(x+3); // doesn't work
}
class DerFoo : public Foo {
protected:
Bar db;
public:
DerFoo(int x);
};
DerFoo::DerFoo(int x) : Foo(x),
db(x+3) // (Bar)(int) being called, works fine
// db(4.0, 30) // no matching function for call to Bar::Bar(double, int)
// note: candidates are Bar::Bar(const Bar&), Bar::Bar(int)
// b(x-3) // doesn't work class DerFoo does not have any field named 'b'
{
//this->b(x - 3); // Doesn't work, error no match for call to (Bar)(int)
//this->db(x + 3); // Doesn't work, error no match for call to (Bar)(int)
}
So the problem as you can see is inside the derived foo class, DerFoo how to initialize b. I have tried member initialization method, but then the compiler doesn't realize about protected variables. So then for some bizarre reason unbeknownst to me, it can not find the constructor in this class. Even though if were to include a "wrong" call to the constructor of a protected member variable (non inherited) it would suggest the correct version of the constructor.
I have no clue still how to do this. Any help is greatly appreciated.
After you declare a variable you have to set it otherwise you will be calling it like a function.
this->b = Bar(x+3);
The preferred way is to use the initializer list to avoid unnecessary copies of Bar. If you do, however, need to set b outside of the constructor the above example is how to do so.
DerFoo's constructors must not (and cannot) initialize b, that's Foo job. DerFoo's constructors are responsible for initializing only DerFoo's immediate subobjects, namely db and the Foo which is a base class of DerFoo. Foo's constructor, in turn, is responsible for initializing b.
The sequence of events is like:
DerFoo's constructor invokes Foo's constructor
Foo's constructor invokes b's constructor
Foo's constructor runs its body, leaving the Foo object completely constructed
DerFoo's constructor invoke's db's constructor
DerFoo's constructor runs its body, leaving the DerFoo object completely constructed.
If, in the DerFoo constructor, you don't like the value that the Foo constructor left in b, you can assign a new value to b, using any one of these syntaxes:
b = Bar(47);
this->b = Bar(47);
this->Foo::b = Bar(47);
Foo::b = Bar(47);
I don't find the question very clear, but let's see if I understood what you are trying to do and how.
DerFoo::DerFoo(int x) : Foo(x), [a]
db(x+3)
// db(4.0,30) [1]
// note: candidates are Bar::Bar(const Bar&), Bar::Bar(int)
// b(x-3) [2]
{
//this->b(x - 3); [3]
//this->db(x + 3); [4]
}
The first error is [1], where the compiler is telling you that there is no constructor of Bar that takes both a double and an int. The error also lists the two possible constructors that you can use: Bar(int), Bar(Bar const &). I am unsure as of what you intended with this line, but you have already figured out (previous line) that by just providing an int the call will work.
[2] b is not a member of DerFoo, and thus cannot be initialized in the initializer list of DerFoo. It is the responsibility of Foo to initialize it's own member and that will happen through the call to the Foo constructor in [a].
[3],[4], both expressions take the form this->member(i). During initialization the syntax member(i) will well, initialize member with the value of i. Outside of initialization the syntax means call operator()( int ) passing the value of i. Those members have already been initialized, but if you want to reset them you need to assign rather than initialize them.
b is inside the Foo class. to access it (for sure) use
Foo::b = Bar(x-3);
You don't have to use an initializer list, you definitely also should use an initializer list at this point.
At construction of an object, before the code of the constructor is entered all member variable are already constructed. If you don't give initializers, they will be default constructed.
Also you cannot construct a variable again, after it already has been constructed. Your
this->b(x+3)
is not telling the compile to construct b it is telling it to call a function named b on your object. Such a function does not exist in your class, hence the error. Note that once an object has been constructed into a variable, there is no way, to ever call the constructor for that variable again (only to change the value).
A value can be changed using = as in most languages. Hence you could do:
Foo::Foo(int x)
{
this->b = Bar(x+3);
}
This means you are creating another nameless Bar object and assigning it's value to this->b. You should be aware, that this means, you will create two Bar objects, when creating a Foo. First the default constructed one, before. The constructor code is entered, then the new nameless one. Then you will finally assign the value to the already constructed object, so this code is much more inefficient than the one, which uses initializer lists.
EDIT:
Since I missed the second doesn't work in the code above here some additional information:
You are also trying to initialize b directly in the constructor of the derived DerFoo object. However once this part of code is reached, it has already been constructed. Hence any attempt to construct it in the derived constructor comes to late.
Hence you either have to add another constructor to Foo which takes the value and use that one in your constructor of DerFoo. This solution is preferable, since it will only construct the Bar object in b once. If you cannot add such a constructor, then you need to use an assignment in the constructor code for DerFoo.
Trying to initialize b directly in the DerFoo constructor will not work even if the scoping operator is used.
DerFoo::DerFoo() : Foo::b(x-3) {}
will still produce an error: http://ideone.com/6H8ZD
I have a member of class A in my own class which constructor takes multiple parameters. Im forwarding parameters of my own class to the constructor of class A. But its important that these parameters are correct, so i need to check them before consructing the member of A. And heres the problem:
I could leave out the member in the member intialization list, effectively calling the default constructor. After the checks in the constructor i could then call A`s constructor in a assigment. Although, this produces a error since the destructor of A is private.
How do i solve this?
MyClass::MyClass(int someParam) : otherMember(2){
//checks for someParam
member = A(someParam); // <- produces error
}
You're going to need an accessible destructor no matter what you do. But to address your question, one option would be to call a static function to check parameters from within the initializer:
class MyClass {
private:
static void checkParam(int);
// ...
};
MyClass::MyClass(int someParam) : otherMember( (checkParam(someParam), 2) ) {
// ...
}
static void MyClass::checkParam(int someParam) {
if (...) throw someException();
}
Note that the , used there is the comma operator, not an argument separator - it evaluates both left and right expressions, and throws away the result of the left.
I see two ways of approaching this:
Make sure class A can be used with a parameter-less constructor, and set someParam in a separate method: A.SetSomeParam(someParam)
Not inherit from A, but rather hold a member object of type A, and then you can construct it whenever you like.