C++: Initializing class member variable with reference to another class member variable? - c++

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.

Related

How c++ resolve name in this case? [duplicate]

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;
}
};

uninit_member: Non-static class member field m_cJobState.bstatus is not initialized in this constructor nor in any functions that it calls

I am getting the below warning at SubManager constructor:
Uninitialized scalar field (UNINIT_CTOR)
uninit_member: Non-static class member field m_cJobState.bEULA is not initialized in this constructor nor in any functions that it calls.
uninit_member: Non-static class member field m_cJobState.bstatus is not initialized in this constructor nor in any functions that it calls.
uninit_member: Non-static class member field m_cJobState.eActivationState is not initialized in this constructor nor in any functions that it calls.
Below is the code snippet:
SubManager.h file
struct MgrStatus
{
bool bEULA;
bool bstatus;
WorkState eActivationState;
};
class SubManager
{
private:
MgrStatus m_cJobState;
};
SubManager.cpp file
SubManager::SubManager()
{
}
To resolve the warning,
Do we need to initialize structure variables in the above constructor?
If we need to initialize, how to initialize the enum variable (WorkState eActivationState;)?
You did not specify from what tool you got warnings and also posted code
should give different errors I suspect. Seems that the tool requires you to initialize all aggregate members in constructors (C++ standard does not).
Since C++11 (question was tagged like that) it should compile and run with uniform initialization of aggregate members:
enum WorkState {SomethingElse, Crappy, Etc}; // wasn't defined in OP
struct MgrStatus
{
bool bEULA;
bool bstatus;
WorkState eActivationState;
};
class SubManager
{
public:
SubManager(); // constructor declaration was missing in OP
private:
MgrStatus m_cJobState;
};
SubManager::SubManager()
: m_cJobState{false,false,Crappy}
{ }
int main() // to demo it runs
{
SubManager s;
(void)s; // just to silence unused variable s warning
}

Is it safe to initialize a member using a member initialized earlier in initializer list?

Is the following code safe or does it lead to undefined behavior in C++03?
class Aries {
public:
Aries() : Taurus("foo") , Leo(Taurus + "bar") {}
private:
string Taurus;
const string Leo;
};
This code is obviously a stripped down version of my actual problem.
Edit Taurus has been intentionally declared before Leo in the class declaration. I am aware the initialization happens in the order of initialization in class declaration (not the order in the initializer list.)
Just to clarify an alternative I mentioned in the comments:
class Aries {
public:
friend Aries makeAries() {
string Taurus = "foo"; // easier to do computations here:
return Aries( Taurus, Taurus + "bar" );
}
private:
Aries( string const &inTaurus, string const &inLeo )
: Taurus(inTaurus) , Leo(inLeo) {}
string Taurus;
const string Leo;
};
Aries makeAries(); // must declare a friend factory outside the class
This isn't a universal solution or a really desirable idiom, but can still be helpful and relatively clean.
Yes, you can safely use members that are initialized before the member you are initializing.
Note that the order of initialization is the order of declaration in the class definition.

How can static functions be useful?

I don't get all these keywords. Specially this one static. An example of how important it is and how it used would be wonderful.
Making a member function static allows you to call the function without creating the class object.
class MyClass
{
int i;
static MyClass *ptr;
static MyClass* getInstance()
{
if(NULL == ptr)
{
ptr = new MyClass();
}
return ptr;
}
};
MyClass* MyClass::ptr = NULL;
int main()
{
MyClass *ptr = MyClass::getInstance();
}
Check out the Singleton pattern for more information on how it can be helpful.
static member functions are just like regular functions.
class Sample
{
public:
static void DoWork()
{
cout << "Static Member Function"<< endl;
}
};
//access
Sample::DoWork();
Output:
Static Member Function
You can treat them just like regular functions, that means, you can pass them to other functions which accept only regular function as argument, like this:
typedef void (*Worker)();
void Fun(Worker worker)
{
//call here just like regular function
worker(); //note: class name is not needed even if you pass static member function!
}
//pass static member function!!
Fun(Sample::DoWork);
Output:
Static Member Function
There are multiple uses for the static keyword, it does different things based on where you use it.
http://msdn.microsoft.com/en-us/library/s1sb61xd.aspx
When you declare a variable or
function at file scope (global and/or
namespace scope), the static keyword
specifies that the variable or
function has internal linkage. When
you declare a variable, the variable
has static duration and the compiler
initializes it to 0 unless you specify
another value.
When you declare a variable in a
function, the static keyword specifies
that the variable retains its state
between calls to that function.
When you declare a data member in a
class declaration, the static keyword
specifies that one copy of the member
is shared by all instances of the
class. A static data member must be
defined at file scope. An integral
data member that you declare as const
static can have an initializer.
When you declare a member function in
a class declaration, the static
keyword specifies that the function is
shared by all instances of the class.
A static member function cannot access
an instance member because the
function does not have an implicit
this pointer. To access an instance
member, declare the function with a
parameter that is an instance pointer
or reference.
Static classes and class members are used to create data and functions that can be accessed without creating an instance of the class. The advantage is that you don't need to instantiate the class to use methods or properties.
An example of when to use a static class might be for utility functions such as converters (e.g. Fahrenheit to Celcius). This type function doesn't change irregardless of any object or data.
In C# you can call a static method like this:
double F, C = 0
// TempConverter converter = new TempConverter(); <-- NOT NEEDED FOR STATIC
F = TempConverter.CelsiusToFahrenheit("100.0");
C = TempConverter.FahrenheitToCelcius("212.0");
Here is how the static class and methods are defined:
public static class TemperatureConverter {
public static double CelsiusToFahrenheit(string temperatureCelsius) {
.. conversion code..
}
public static double FahrenheitToCelsius(string temperatureFahrenheit) {
.. conversion code..
}
}
There are two types of static functions: class/struct member, and non-member. I guess you're wondering about the former (as it's more confusing)...
static member functions
If we contrast four functions:
class X
{
....
int non_static_member_f(X& a) { ... }
static int static_member_f(X& a) { ... }
friend int non_member_friend_f(X& a) { ... }
};
int non_member_f(X& a) { ... }
And given:
X x, arg;
We can write:
x.non_static_member_f(arg) - x is an existing X object instance - made accessible via the this pointer. The function has full access to all private/protected/public static/non-static members of X for operations on x and arg.
X::static_member_f(arg) can be invoked with a single X argument - if the function didn't specify an X argument, then it could be called with no existing X objects. It has full access to all private/protected/public static of X, and can access any non-static members on arg.
non_member_friend_f(arg) has the same access as X::static_member_f(arg), but is not scoped inside X (i.e. you don't need to call it with the X:: prefix, Koenig lookup resolves differently).
non_member_f(arg) can only access the public members of arg, and has no special privileges.
For completeness: static non-member functions differ from non-static in having internal linkage, which means they're not callable from other translation units but won't clash with any same-named function in those translation units.
Static functions are very useful when implementing so-called Named Constructors.
Imagine a Point class which can be either constructed from rectangular coordinates (X/Y) or polar coordinates (radius and angle):
class Point {
public:
Point(float x, float y); // Rectangular coordinates
Point(float r, float a); // Polar coordinates (radius and angle)
// ERROR: Overload is Ambiguous: Point::Point(float,float)
};
int main()
{
Point p = Point(5.7, 1.2); // Ambiguous: Which coordinate system?
...
}
This can be solved very nicely using static functions which create Point objects; such functions are called named constructors since they act like a constructor (they produce a new object) but they can have a descriptive name:
class Point {
public:
// These static methods are the so-called "named constructors"
static Point rectangular(float x, float y) { return Point(x, y); }
static Point polar(float radius, float angle) { return Point(radius*std::cos(angle), radius*std::sin(angle)); }
// ...
private:
Point(float x, float y) : x_(x), y_(y) { }
float x_, y_;
};
Clients of the class can now use these named constructors to create readable, unambiguous code:
int main()
{
Point p1 = Point::rectangular(5.7, 1.2); // Obviously rectangular
Point p2 = Point::polar(5.7, 1.2); // Obviously polar
}
Furthremore, named constructors can be used to make sure that objects of a class are always allocated with new (so that you know that you can always call delete on them). See FAQ [16.21] for more information.
static class member functions are useful:
For implementing the Factory Method Pattern
For implementing the Singleton Pattern
For loose decoupling of functions that may polute the behaviour of the class. ( Functions not necessarily members can be declared static... but even better they could be totally classic functions!) cf S.R.P.
Can be used as a function to be passed as a plain C function pointer so as to inter-operate with C code...
static functions are useful:
1. to avoid duplicate code redefinition while compiling. A static function will be redefined for each cpp unit it is included in.
And I think there are tons of other useful cases I don't remember of right now :-)
The answer from martona is a good overview of static. Relating to static members, I think Tony covers it pretty well.
The mental model I use when it comes to member functions is to consider how they might be modeled in 'C':
class A
{
public:
void mbr_1 ();
void mbr_2 () const;
void mbr_3 () volatile;
void mbr_4 () const volatile;
static void mbr_5 ();
};
Might be implemented as:
struct A { };
void mbr_1 (A * const this);
void mbr_2 (A const * const this);
void mbr_3 (A volatile * const this);
void mbr_4 (A const volatile * const this);
void mbr_5 ();
All the funcitons are members and so have appropriate 'access' to private members. The non static members have a 'this' pointer, and it is that which provides the access to a specific instances members. The static member doesn't have such a pointer and this is why we cannot access any non static members.

Can I use identical names for fields and constructor parameters?

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;
}
};