This is probably a very basic question but I never got around to understanding it properly. When I declare member variables I usually do within a class
class Bloke
{
public:
Bloke(): age(24) {}
int age;
}
So, I usually declare after the semicolon the member variables with "membera(), memberb()" etc. Over time I got a bit lazy and started to also include declarations of the member variables directly in {}, that is
Bloke(){age=24;}
int age;
Or even outside the class in the constructor separately. Can someone please explain if this is wrong? Thanks.
No it is not wrong and up until c++11 it was the only way. Most people however would consider the first way to be easier and more idiomatic for c++11, it is called constructor delegation. In c++11 you can also do inline initialization for some types like this:
class Bloke
{
public:
Bloke():{}
int age = 24;
};
The value for age will be 24 unless you change it somewhere else for all initialized objects. IMO constructor delegation should be used for any situation where applicable and save the body of the constructor for extra work.
Related
I am curious as to whether any clarification can be provided on the multitudes of constructor syntax's there are in C++. I have seen constructors declared inside of classes, and outside of classes. I have also seen variable initialization through more common methods such as x = y or this-> x = y, but also through initialization lists, like Point(int i = 0):x(i) {}.
My question is whether there are certain situations where it is more suitable to use one style of constructor over another, or whether to declare the constructor inside or outside the class. Is their some commonly followed syntax guideline for this?
I feel it is generally a good idea to have constructors' destructors and other methods' prototypes inside the class itself, if they belong to the same class. It is more efficient and more programmer friendly.
for eg:
I would do something like this:
class decl ....{
private:
members var.. methods' prototype..
public:
decl(); default cons prototype
decl(type para....); parameterized cons prototype;
~decl();
some methods' prototypes..
};
Then you can always go ahead and use them take an argument to assign the value to instant variable
such as this:
decl::decl(can user the same name or different ){
if using the same name
this -> sameName = sameName;
otherwise,
instant data variable name = assign the value,
}
Say there is a class:
class person {
int age;
string name;
public:
person(int age,string name)
:age(age),name(name)
{}
};
I have the following questions:
Can the constructor initializer(with the ":" syntax) be used somehow outside of classes?Is it just for classes?
A variable declaration such as int x(2) works for obvious reasons.x is an object with value of 2.But age(age),how does that work?Is the syntax made that way to make initialization easier?
Based on that,how come can the parameter age & member age have the same name and not confuse the compiler?Member age is in scope(as a private member),but parameter age is also in scope.When this happens with ordinary functions,the "localest" is the one that prevails.
Thanks!
It doesn't 'confuse' the compiler. Since it's a member initializer list it's scope is the same as constructor. Therefore function scope wins over class scope. And therefore the member age is initialized with the paramter age.
Normally I would not use the same name (even though certainly possible) as it's both brittle and somewhat unclear. For example:
struct Decision {
bool launch_nukes;
Decision(bool /*launch_nukes*/) : launch_nukes(launch_nukes) {
}
};
At best will only give a warning.
Can the constructor initializer(with the ":" syntax) be used somehow outside of classes?Is it just for classes?
Member initializer lists can only be used by constructors only.
A variable declaration such as int x(2) works for obvious reasons.x is an object with value of 2. But age(age), how does that work? Is the syntax made that way to make initialization easier?
Based on that,how come can the parameter age & member age have the same name and not confuse the compiler? Member age is in scope, but parameter age is also in scope. When this happens with ordinary functions, the "localest" is the one that prevails.
we have and expect member(init), so for member, only members of the class are seen (and Base class or own class for delegating constructor). We can say that we are only in the scope of the class.
For init, indeed regular scope applies, and parameters age/name hides members with same name.
first here is the example Code:
cPerson.h:
#pragma once
class cPerson
{
public:
cPerson();
~cPerson();
int Age;
};
cPerson.cpp
#include "cPerson.h"
cPerson::cPerson()
{
this->Age = 3; // Way 1
cPerson::Age = 4; // Way 2
}
cPerson::~cPerson() { }
Ok now my Question:
If we are defining a new Class in C++ there are two ways to set the initial Values. There is (Way 1) by using the "this"-pointer, or (Way 2) using the scope operator ( :: ).
In school I learned it using "this->". Now, years after not using C++, I startet to get into it again and found this second way, using the scope operator.
Both way work fine BUT what's the exact difference between them and what's the "faster"/"better" way? I'm that kind of guy who likes to know what exactly is going on in my ram/cpu if I'm programming.
So I hope someone can help me out, and thanks in advance.
A better way to write the constructor as
cPerson::cPerson() : Age(3)
{
}
since then you can construct a const instance of your object. Consider starting Age with a lower case letter: this would be more conventional.
You could refine your first way by writing the more succinct Age = 3;: sometimes initialising members in the constructor body is unavoidable if they depend on the result of complex calculations.
Using :: is idiosyncratic: using the scope resolution operator will fail if the member is defined in a base class. But it does have occasional usage, particularly if you need to disambiguate a shadowed base class member.
Finally, from C++11 onwards you could simplify your class to
struct cPerson
{
int Age = 3;
};
See C++11 allows in-class initialization of non-static and non-const members. What changed?
Rather surprised to find this question not asked before. Actually, it has been asked before but the questions are VERY DIFFERENT to mine. They are too complicated and absurd while I'll keep it simple and to the point. That is why this question warrants to be posted.
Now, when I do this,
struct A {
int a = -1;
};
I get the following error:
ANSI C++ forbids in-class initialization of non-const static member a
Now, along with the workaround can someone please tell me THE BEST way of initializing a struct member variable with a default value?
First, let's look at the error:
ANSI C++ forbids in-class initialization of non-const static member a
Initialization of a true instance member, which resides within the memory of an instance of your struct is the responsibility of this struct's constructor.
A static member, though defined inside the definition of a particular class/struct type, does not actually reside as a member of any instances of this particular type. Hence, it's not subject to explaining which value to assign it in a constructor body. It makes sense, we don't need any instances of this type for the static member to be well-initialized.
Normally, people write member initialization in the constructor like this:
struct SomeType
{
int i;
SomeType()
{
i = 1;
}
}
But this is actually not initialization, but assignment. By the time you enter the body of the constructor, what you've done is default-initialize members. In the case of a fundamental type like an int, "default-initialization" basically boils down to "eh, just use whatever value was in those bytes I gave you."
What happens next is that you ask i to now adopt the value 1 via the assignment operator. For a trivial class like this, the difference is imperceptible. But when you have const members (which obviously cannot be tramped over with a new value by the time they are built), and more complex members which cannot be default-initialized (because they don't make available a visible constructor with zero parameters), you'll soon discover you cannot get the code to compile.
The correct way is:
struct SomeType
{
int i;
SomeType() : i(1)
{
}
}
This way you get members to be initialized rather than assigned to. You can initialize more than one by comma-separating them. One word of caution, they're initialized in the order of declaration inside your struct, not how you order them in this expression.
Sometimes you may see members initialized with braces (something like i{1} rather i(c)). The differences can be subtle, most of the time it's the same, and current revisions of the Standard are trying to smooth out some wrinkles. But that is all outside the scope of this question.
Update:
Bear in mind that what you're attempting to write is now valid C++ code, and has been since ratification of C++11. The feature is called "Non-static data member initializers", and I suspect you're using some version of Visual Studio, which still lists support as "Partial" for this particular feature. Think of it as a short-hand form of the member initialization syntax I described before, automatically inserted in any constructor you declare for this particular type.
You could make a default constructor
struct A {
A() : a{-1} {}
int a;
};
I have always been a good boy when writing my classes, prefixing all member variables with m_:
class Test {
int m_int1;
int m_int2;
public:
Test(int int1, int int2) : m_int1(int1), m_int2(int2) {}
};
int main() {
Test t(10, 20); // Just an example
}
However, recently I forgot to do that and ended up writing:
class Test {
int int1;
int int2;
public:
// Very questionable, but of course I meant to assign ::int1 to this->int1!
Test(int int1, int int2) : int1(int1), int2(int2) {}
};
Believe it or not, the code compiled with no errors/warnings and the assignments took place correctly! It was only when doing the final check before checking in my code when I realised what I had done.
My question is: why did my code compile? Is something like that allowed in the C++ standard, or is it simply a case of the compiler being clever? In case you were wondering, I was using Visual Studio 2008
Yes, it's valid. The names in the member initializer list are looked up in the context of the constructor's class so int1 finds the name of member variable.
The initializer expression is looked up in the context of the constructor itself so int1 finds the parameter which masks the member variables.
What you have done is standard C++. Only member variables or base classes may be initliazed in the initialization list, so the variable outside the paranthesis is unambiguous. Within the parenthesis, the typical scoping rules apply, and the members are overshadowed by the parameter names.
This is perfectly normal behavior. As AAT rightly pointed out, there is no ambiguity. The variables initialised by the list have to be class members. This is standard and works across all compliant compilers.
The only thing to remember while using a list like this is that a person who doesn't understand this kind of code may have to maintain it. There is nothing wrong with writing initialisation code like this as long as you know what you are doing.
I imagine this works because you were using int1 in the initialiser list, and the only things you can initialise are member variables => it was in fact unambiguous which variable was being initialised.
Whether all C++ compilers would be this forgiving is another matter!
What you have done is normal. This kind of implementation avoids you from even using the 'this' pointer (in this case).