class C {
T a;
public:
C(T a): a(a) {;}
};
Is it legal?
Yes it is legal and works on all platforms.
It will correctly initialize your member variable a, to the passed in value a.
It is considered by some more clean to name them differently though, but not all. I personally actually use it a lot :)
Initialization lists with the same variable name works because the syntax of an initialization item in an initialization list is as follows:
<member>(<value>)
You can verify what I wrote above by creating a simple program that does this: (It will not compile)
class A
{
A(int a)
: a(5)//<--- try to initialize a non member variable to 5
{
}
};
You will get a compiling error something like: A does not have a field named 'a'.
On a side note:
One reason why you may not want to use the same member name as parameter name is that you would be more prone to the following:
class A
{
A(int myVarriable)
: myVariable(myVariable)//<--- Bug, there was a typo in the parameter name, myVariable will never be initialized properly
{
}
int myVariable;
};
On a side note(2):
One reason why you may want to use the same member name as parameter name is that you would be less prone to the following:
class A
{
A(int myVariable_)
{
//<-- do something with _myVariable, oops _myVariable wasn't initialized yet
...
_myVariable = myVariable_;
}
int _myVariable;
};
This could also happen with large initialization lists and you use _myVariable before initializing it in the initialization list.
One of the things that may lead to confusion regarding this topic is how variables are prioritized by the compiler. For example, if one of the constructor arguments has the same name as a class member you could write the following in the initialization list:
MyClass(int a) : a(a)
{
}
But does the above code have the same effect as this?
MyClass(int a)
{
a=a;
}
The answer is no. Whenever you type "a" inside the body of the constructor the compiler will first look for a local variable or constructor argument called "a", and only if it doesn't find one will it start looking for a class member called "a" (and if none is available it will then look for a global variable called "a", by the way). The result is that the above statment "a=a" will assign the value stored in argument "a" to argument "a" rendering it a useless statement.
In order to assign the value of the argument to the class member "a" you need to inform the compiler that you are referencing a value inside this class instance:
MyClass(int a)
{
this->a=a;
}
Fine, but what if you did something like this (notice that there isn't an argument called "a"):
MyClass() : a(a)
{
}
Well, in that case the compiler would first look for an argument called "a" and when it discovered that there wasn't any it would assign the value of class member "a" to class member "a", which effectively would do nothing.
Lastly you should know that you can only assign values to class members in the initialization list so the following will produce an error:
MyClass(int x) : x(100) // error: the class doesn't have a member called "x"
{
}
if the formal parameter and the member is named same then beware of using this pointer inside constructor to use the member variable
class C {
T a;
public:
C(T a): a(a) {
this->a.sort ;//correct
a.sort();//will not affect the actual member variable
}
};
Legal: yes, as explained by Brian, compiler knows the name to expect in the initializer list must be a member (or a base class), not anything else.
Good style: most likely not - for a lot of programmers (including you, it seems) the result is not obvious. Using a different name for the parameter will keep the code legal and make it a good style at the same time.
I would prefer writing some of:
class C {
T a_;
public:
C(T a): a_(a) {}
};
class C {
T a;
public:
C(T value): a(value) {}
};
The problem with this practice, legal though it may be, is that compilers will consider the variables shadowed when -Wshadow is used, and it will obfuscate those warnings in other code.
Moreover, in a non-trivial constructor, you make make a mistake, forgetting to put this-> in front of the member name.
Java doesn't even allow this. It's bad practice, and should be avoided.
Hey guys this is a great question. If you want to identical names for fields and constructor parameters / methods parameter you have to use scope resolution ( :: ) operator or you can use this ( this-> ) to map the parameter value with member like this please check the code snippet carefully you can understand easyly.
class Student{
private :
string name;
int rollNumber;
public:
Student()
{
// default constructor
}
// parameterized constructor
Student(string name, int rollNumber)
{
this->name = name;
Student::rollNumber = rollNumber;
}
void display()
{
cout<<"Name: "<<name <<endl;
cout<<"Roll Number: "<<rollNumber<<endl;
}
void setName(string name)
{
this->name = name;
}
void setrollNumber(int rollNumber)
{
Student::rollNumber = rollNumber;
}
};
Related
This question already has answers here:
What is this weird colon-member (" : ") syntax in the constructor?
(14 answers)
Closed 4 years ago.
What's the difference between these two declarations of constructors:
class Fruit {
private:
int price;
public:
Fruit(int x): price(x)
{
}
};
VS
class Fruit {
private:
int price;
public:
Fruit(int x)
{
price = x;
}
};
The first one I have seen in case of inheritance.
As per my knowledge, this is not a duplicate question. If you find one feel free to close this question.
The first one initialize price with x where the second one initialize price with its default value (default construct it; in case of a int variable, is initialized with an undefined value) and then copy x in price.
In other words, the first one is almost equivalent to
int price = x;
where the second one is almost equivalent to
int price;
price = x;
In case of a int variable (taking also in count the compiler's optimizations) I suppose there isn't an effective difference.
But when price is a complex object, with an heavy construction cost, there can be a great difference.
As better explain Peter, "It's not construction cost that makes the difference between the two for complex objects. It is a question of whether reassigning after default initialisation is more costly than initialising in one step. Practically, the two stage process is often more expensive (by various measures) than direct initialisation, since it can be necessary to clean up the default setting in order to change the value. There are also concerns of exception safety - what if reassignment or construction throws an exception."
So, usually, is strongly suggested to use the first solution (initialize the object with the right value).
See also the Zereges's answer that point the attention over the fact that the first one method is the only available to assign a value to a constant member.
Indeed you can't write
int const price;
price = x; // error: price is const
The first one uses an initialization list, while the other doesn't, and assigns x to the data member price inside the body of the constructor.
We usually prefer to use initialization lists, and to keep the body of the constructor as simple as possible.
To add up to other answers, the first option is the natural way to initialize const members
struct C
{
const int val;
C() : val(5) // Perfectly OK
{
}
C(int) // error: uninitialized const member in 'const int' [-fpermissive]
{
val = 5 // error: assignment of read-only member 'C::val'
}
};
Also, when class has members of type, that are not default-constructible, this is the way to initialize them
struct D
{
struct not_default_constructible
{
not_default_constructible(int)
{
}
} var;
int& ref;
D(int a) : ref(a), var(5) // Legal
{
}
D(int a, char) // error: uninitialized reference member in 'int&' [-fpermissive]
{ // error: no matching function for call to 'D::not_default_constructible::not_default_constructible()'
ref = a;
}
};
The second one does not initialize price with x when a Fruit is created which therefor default constructs it. Just as if you'd written:
class Fruit{
private :
int price
public:
Fruit(int x) :
price() // default constructed
{
price = x
}
}
For effectiveness, it's better to initialize with the value you want to assign to it.
I am attempting to make a class in c++ called to store values for a number of parameters that are organized as member variables of class 'Planet' and class 'Satellite', which I want to initialize with a reference to an instance of 'Planet'. Here I provide an example where I have a 'PlanetCatalog' class with
member variables 'Planet neptune' and a 'Satellite triton'.
class Planet {
public:
double a;
Planet() {}
void setParams( const double a_) {
a = a_;
}
};
class Satellite {
public:
double b;
Planet & planet;
Satellite( Planet & planet_):planet(planet_) { }
void setParams(const double b_) {
b = b_;
}
};
class PlanetCatalog {
public:
Planet neptune;
Satellite triton(neptune);
void setAll() {
neptune.setParams(1.);
triton.setParams(2.);
}
};
However, upon compiling I encounter the error.
error: unknown type name 'neptune'
Satellite triton(neptune);
Is it possible to have the Planet and Satellite stored as variables of the same class as I have done here. If not, could someone suggest a better way of organizing this functionality in c++?
Use of parentheses for in-class initialization makes compiler treat triton as a non-static member function declaration with neptune being type of the first argument, you should use list-initialization syntax instead:
Satellite triton{neptune};
Note that there is actually no need to define PlanetCatalog constructor for this.
What happened?
class PlanetCatalog {
public:
...
Planet neptune;
Satellite triton(neptune); //<-- Compiler sees this as a non-static member-function declaration
...
Because of the context of that statement, the compiler sees it as a non-static member-function declaration and tries to find such type named neptune within the relevant namespace(s); It issues an error since it can't find it.
Option 1: You can define a constructor that initializes triton for you in its member-initialization-list
class PlanetCatalog {
public:
...
Planet neptune;
Satellite triton;
PlanetCatalog() : triton(neptune) {}
...
Note: using this option, the order of your class data members matters, because the order initialization of data members is defined by their order of declaration in the class, not by the order of initialization in the member-initialization-list
Option 2: Another straightforward solution will be to use copy-initialization
Satellite triton = neptune;
Option 3: or list-initialization
Satellite triton{neptune};
Options 2 and 3 are preferable because it forces the declaration order implicitly.
I am coming from the Java background. I have the following program.
#include <string>
#include <iostream>
class First {
public:
First(int someVal): a(someVal) {
}
int a;
};
class Second {
public:
First first;
Second() { // The other option would be to add default value as ": first(0)"
first = First(123);
}
};
int main()
{
Second second;
std::cout << "hello" << second.first.a << std::endl;
}
In class Second, I wanted to variable first to remain uninitialized until I specifically initialize it in Second()'s constructor. Is there a way to do it? Or am I just left with 2 options?:
Provide a parameter-less constructor.
Initialize it with some default value and later re-assign the required value.
I can't initialize first in the initializer-list with the right value, since the value is obtained after some operation. So, the actual required value for first is available in Second() constructor only.
MY suggestion: Use a function:
private: static int calculate_first(int input) {return input*5;}
explicit Second(int input) : first(calculate_first(input)) {}
Base classes will be initialized in the order they're declared in the class inheritance list, and then members will be initialized in the order that they're listed in the class, so the calculation can depend on non-static member-variables and base classes if they have already been initialized.
Alternatively:
Default constructor, then reassign:
explicit Second(int input) { first = input*5; }
Dummy value, then reassign:
explicit Second(int input) : first(0) { first = input*5; }
Use boost::optional (or std::optional as of C++17):
boost::optional<First> first;
explicit Second(int input) { first = input*5; }
Use the heap:
std::unique_ptr<First> first;
explicit Second(int input) { first.reset(new First(input*5));}
Second(const Second& r) first(new First(*(r->first))) {}
Second& operator=(const Second& r) {first.reset(new First(*(r->first)));}
Placement new:
This is tricky and not suggested
and worse in every way than boost::optional
So sample deliberately missing.
But it is an option.
Initialize first in the member initializer list.
It may help to perform your calculations in a helper function and use a forwarding constructor:
class Second {
public:
Second() : Second(helper_function()) {}
private:
Second(int calc): first(calc) {}
static int helper_function() { return ...; }
First first;
};
This sentence is the core of the problem:
I can't initialize first in the initializer-list with the right value,
since the value is obtained after some operation.
You should know that what you want to do here is not perfect programming style in Java, either. Leaving the field with some default value and then assigning it a bit later after some calculations have been done effectively prevents it from being final, and consequently the class from being immutable.
In any case, your goal must be to push those calculations directly into the initialization of the member, using private helper functions (which may be static):
class Second {
private:
First first;
static int getInitializationData()
{
// complicated calculations go here...
return result_of_calculations;
}
public:
Second() : first(getInitializationData()) {}
};
In my opinion, everything else is just a workaround and will complicate your life in the long run.
You can just do what you said in the comments, or, you can make first a pointer to First and give it memory whenever you like, although i don't recommend this way
One way to separate object lifetimes is to use the heap, make first a pointer and initialize it anytime you like:
class Second {
public:
First* first;
Second() {
first = new First(123);
}
};
of course, you'll probably want to use a smart pointer of some sort rather than a raw pointer.
If you don't code to explicitly initialize a member variable, the default initializer is used to initialize it.
The draft C++ standard has the following about initialization of base classes and member variables:
12.6 Initialization [class.init]
1 When no initializer is specified for an object of (possibly cv-qualified) class type (or array thereof), or the initializer has the form (), the object is initialized as specified in 8.5.
And
12.6.1 Explicit initialization [class.expl.init]
1 An object of class type can be initialized with a parenthesized expression-list, where the expression-list is construed as an argument list for a constructor that is called to initialize the object. Alternatively, a single assignment-expression can be specified as an initializer using the = form of initialization. Either direct-initialization semantics or copy-initialization semantics apply; see 8.5.
I want to know what's difference in the following two class.
example 1:
class A
{
string name;
public:
A(const char* _name):name(_name){}
void print(){cout<<"A's name:"<<name<<endl;}
};
example 2:
class A
{
string name;
public:
A(const char* _name){name(_name);}
void print(){cout<<"A's name:"<<name<<endl;}}
why the example 1 is passed and the last one is wrong?
Thanks
In example 1 you initialize the string with the given value right away.
In example 2 you create an empty string first and assign it later on.
Despite some performance differences and ignoring possible differences due to copy constructor handling etc. it's essentially the same result.
However once you use a const member you'll have to use example 1's way to do it, e.g. I usually create unique IDs the following way:
class SomeObject
{
static unsigned int nextID = 0;
const unsigned int ID;
SomeObject() : ID(nextID++)
{
// you can't change ID here anymore due to it being const
}
}
The first example is an actual initialization. It has a number of advantages, including being the only way to set up const members, and having proper exception-safety.
The second example is not valid C++, AFAIK. If you had instead written name = name_, then this would just be normal assignment. Of course, this isn't always possible; the object might be const, or not have an assignment operator defined. This approach could also be less efficient that the first example, because the object is both default-initialized and assigned.
As for why the initializer list is before the constructor body; well, that's just the way the language has been defined.
That's just how the language is defined. The member initializers should be placed before the body of the constructor.
In the first example the member name is initialized with a ctr getting char * as parameter.
In the second case it is initialized with a default ctr at first and it gets value by the assignment operator (operator=) later. That's why it is wrong with your case that it is already constructed there so you can not use the ctr once again you could just use the assignment operator.
The reason is that name lookup works different in initializer lists and function bodies:
class A
{
std::string foo; // member name
public:
A(const char* foo) // argument name
: foo(foo) // member foo, followed by argument foo.
{
std::cout << foo; // argument foo.
}
};
If the initializer list was inside the function body, there would be an ambiguity between member foo and argument foo.
The motivation behind the initialization list is due to const field holding a object by value (as opposed to reference/pointer field).
Such fields must be initialized exactly once (due to their const-ness). If C++ didn't have initialization list then a ctor would look something like:
class A {
public:
const string s;
const string t;
A() {
// Access to either s or t is not allowed - they weren't initialized
s = "some-string";
// now you can access s but you can't access t
f(*this);
t = "some other string";
// From now you can access both ...
}
}
void f(A& a) {
// Can you access a.s or a.t?
cout << a.s << a.t;
}
Without an initialization list a ctor can pass a partially-initialized object of type A to a function, and that function will have no way of knowing which fields are initialized yet. Too risky and very difficult for the compiler/linker to check.
class C {
T a;
public:
C(T a): a(a) {;}
};
Is it legal?
Yes it is legal and works on all platforms.
It will correctly initialize your member variable a, to the passed in value a.
It is considered by some more clean to name them differently though, but not all. I personally actually use it a lot :)
Initialization lists with the same variable name works because the syntax of an initialization item in an initialization list is as follows:
<member>(<value>)
You can verify what I wrote above by creating a simple program that does this: (It will not compile)
class A
{
A(int a)
: a(5)//<--- try to initialize a non member variable to 5
{
}
};
You will get a compiling error something like: A does not have a field named 'a'.
On a side note:
One reason why you may not want to use the same member name as parameter name is that you would be more prone to the following:
class A
{
A(int myVarriable)
: myVariable(myVariable)//<--- Bug, there was a typo in the parameter name, myVariable will never be initialized properly
{
}
int myVariable;
};
On a side note(2):
One reason why you may want to use the same member name as parameter name is that you would be less prone to the following:
class A
{
A(int myVariable_)
{
//<-- do something with _myVariable, oops _myVariable wasn't initialized yet
...
_myVariable = myVariable_;
}
int _myVariable;
};
This could also happen with large initialization lists and you use _myVariable before initializing it in the initialization list.
One of the things that may lead to confusion regarding this topic is how variables are prioritized by the compiler. For example, if one of the constructor arguments has the same name as a class member you could write the following in the initialization list:
MyClass(int a) : a(a)
{
}
But does the above code have the same effect as this?
MyClass(int a)
{
a=a;
}
The answer is no. Whenever you type "a" inside the body of the constructor the compiler will first look for a local variable or constructor argument called "a", and only if it doesn't find one will it start looking for a class member called "a" (and if none is available it will then look for a global variable called "a", by the way). The result is that the above statment "a=a" will assign the value stored in argument "a" to argument "a" rendering it a useless statement.
In order to assign the value of the argument to the class member "a" you need to inform the compiler that you are referencing a value inside this class instance:
MyClass(int a)
{
this->a=a;
}
Fine, but what if you did something like this (notice that there isn't an argument called "a"):
MyClass() : a(a)
{
}
Well, in that case the compiler would first look for an argument called "a" and when it discovered that there wasn't any it would assign the value of class member "a" to class member "a", which effectively would do nothing.
Lastly you should know that you can only assign values to class members in the initialization list so the following will produce an error:
MyClass(int x) : x(100) // error: the class doesn't have a member called "x"
{
}
if the formal parameter and the member is named same then beware of using this pointer inside constructor to use the member variable
class C {
T a;
public:
C(T a): a(a) {
this->a.sort ;//correct
a.sort();//will not affect the actual member variable
}
};
Legal: yes, as explained by Brian, compiler knows the name to expect in the initializer list must be a member (or a base class), not anything else.
Good style: most likely not - for a lot of programmers (including you, it seems) the result is not obvious. Using a different name for the parameter will keep the code legal and make it a good style at the same time.
I would prefer writing some of:
class C {
T a_;
public:
C(T a): a_(a) {}
};
class C {
T a;
public:
C(T value): a(value) {}
};
The problem with this practice, legal though it may be, is that compilers will consider the variables shadowed when -Wshadow is used, and it will obfuscate those warnings in other code.
Moreover, in a non-trivial constructor, you make make a mistake, forgetting to put this-> in front of the member name.
Java doesn't even allow this. It's bad practice, and should be avoided.
Hey guys this is a great question. If you want to identical names for fields and constructor parameters / methods parameter you have to use scope resolution ( :: ) operator or you can use this ( this-> ) to map the parameter value with member like this please check the code snippet carefully you can understand easyly.
class Student{
private :
string name;
int rollNumber;
public:
Student()
{
// default constructor
}
// parameterized constructor
Student(string name, int rollNumber)
{
this->name = name;
Student::rollNumber = rollNumber;
}
void display()
{
cout<<"Name: "<<name <<endl;
cout<<"Roll Number: "<<rollNumber<<endl;
}
void setName(string name)
{
this->name = name;
}
void setrollNumber(int rollNumber)
{
Student::rollNumber = rollNumber;
}
};