Whenever I define a variable and give it a value at the same time inside a class, I get an error. What is the reason for this?
As you can see, this doesn't work...
class myClass {
private:
int x = 4; // error
};
But when I keep the variable undefined it does:
class myClass {
private:
int x;
};
Since no one else is using member initialization, I'll introduce you:
class myClass {
private:
int x;
public:
myClass() : x (4){}
};
It's always better to use this over assigning in the body of the constructor, since by the time the body begins, all user-defined members will have already been initialized whether you said so or not. Better to do it once and actually initialize the non-user-defined members, and it is the only method that works for both non-static const members, and reference members.
For example, the following will not work because x isn't being initialized in the body, it's being assigned to:
class myClass {
private:
const int x;
public:
myClass() {x = 4;}
};
Using a member initializer, however, will, because you're initializing it off the bat:
class myClass {
private:
const int x;
public:
myClass() : x (4){}
};
Note also that your int x = 4; syntax is perfectly valid in C++11, where it subs in for any needed initialization, so you'll benefit if you start using it.
Initialize your variables in the constructor.
class myClass {
private:
int x;
public:
myClass()
{
x = 4; // hope that it will work
}
};
Updated Answer:
According to chris, it is better to use member initialization
class myClass {
private:
const int x;
public:
myClass() : x (4){}
};
Instance variable are supposed to be defined using setter methods, IE: setX(input) or inside a constructor.
Do this insted:
class myClass
{
private:
static const int x = 4;
};
If you don't x to be either static or constant, use only int x; instead and initialize x in the constructor of the class.
Your class is like a blue print. It does not have any storage associated with it. When you instantiate an object of your class, that is akin to the building based on that blue print. Your object has storage and that can hold the value you give to the member variables.
Also, as others have pointed out, it is possible to do what you want in C++11. Check out:
http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2756.htm
In C++03,
only static const integral data members can be initialized within a
class.
Either initialize in the constructor, or make the data member static const:
class myClass {
private:
int x;
public:
myClass() {
x = 4;
}
};
or
class myClass {
private:
static const int x = 4;
};
Related
What are the ramifications of assigning a class variable when defining the class versus in the class constructor? Is the variable assigned in the class definition accessible by all class instances?
Example of assignment at instantiation:
class Foo
{
private:
int x;
double y;
public:
Foo()
{
x = 0;
y = 1.;
}
};
Example of assignment in class definition:
class Foo
{
private:
int x = 0;
double y = 1.;
public:
Foo();
};
edit:
As to the class member being accessible by all instances, I think I was looking for the notion of a static declaration, I guess I'm just new to the curly brace languages.
In this code snippet
int x = 0;
double y = 1.;
there is no assignments. There are initializations.
In this code snippet
Foo()
{
x = 0;
y = 1.;
}
there is indeed used the assignment operator.
In general for objects of complex types it can be 1) impossible (either the default constructor or the assignment operator is not available) or 2) requiring many resources because at first default constructors are called that create the objects and after that there are called assignment operators.
It is desirable to define constructors at least like for example
Foo() : x( 0 ), y( 1 )
{
}
using mem-initializer lists.
Is the variable assigned in the class definition accessible by all class instances?
No!
The difference is that you default-initialize the member variables and then assign values to them in the first case. In the second case you value-initialize them - which is preferred. A third option, that also value-initializes them, is to use the member-initializer list:
class Foo
{
private:
int x;
double y;
public:
Foo() : x{0}, y{1.}
{
}
};
class myClass
{
private:
struct myStruct
{
int width = 0;
};
public:
myClass();
void changeValue();
};
myClass::myClass()
{
myStruct aStruct;
aStruct.width = 24;
}
void myClass::changeValue()
{
aStruct.width = 23;
}
I made the simple code above in order to test classes. In the member function changeValue i get the error saying that aStruct is not defined. But i don't really understand why it says it's undefined. Previously when i worked with classes this kind of code has worked fine. The difference between then and now is that in the class constructor i used pointers. So does this type of code only work for pointers and not for structs?
The reason i want this to work is it would be really usefull to have this "global" object that belongs to the class that is a struct.
This is not trouble with "understanding classes". You should go back and understand what "scope" is, which is one of basic concept of C++ language.
myStruct aStruct;
belongs to scope of member function myClass::myClass() and ceases to exist when execution of that function ends. This is completely different scope, aStruct variable doesn't exist there.
void myClass::changeValue()
{
aStruct.width = 23; // aStruct doesn't exist in any available scope
}
Now about declarations:
class myClass
{
private:
struct myStruct
{
int width = 0;
};
This code doesn't declare a struct storage inside of classmyClass. It declares member type myStruct (which is a class-type) inside of class myClass.
(Be wary of this name convention, it's very confusing. It's recommended to use capitalization like that only for members. Classes recommended to be all lower case or starting with capital letter.)
class myClass
{
private:
struct myStruct
{
int width = 0;
};
myStruct aStruct; // myClass got field aStruct
public:
myClass() : aStruct {24} {}
void changeValue();
};
aStruct here belongs to the private part of scope of class, which is available for all members of this class. myStruct is also declared as private so can't be used outside of class, be that in child class or just in outer scope.
myClass() : aStruct {24} {}
This is a non-trivial (user-defined) constructor with initializer list. aStruct is field of this class, so it can be initialized with a value like this. It is different from this form
myClass()
{
aStruct.width = 24;
}
In latter case, aStruct would be initialized first (with 0 in width field, as you had instructed) and its constructor will be called, then myClasss constructor would change value of its field to 24.
Before your question gets busted, you got to understand that everything in {} is scoped inside those braces, thus your problem here is that you have:
myStruct aStruct;
inside constructor. So aStruct is local variable to the constructor. In order to fix your code move it just below struct definition.
class myClass
{
private:
struct myStruct
{
int width = 0;
};
// MOVE IT HERE
myStruct aStruct;
public:
myClass();
void changeValue();
};
myClass::myClass()
{
aStruct.width = 24;
}
void myClass::changeValue()
{
aStruct.width = 23;
}
Now all member functions can access aStruct.
I have an object that is created in a .h file that should be initialised in the constructor. This object is passed a COM port number that is 5 in our current application. For this reason I have created a const int in the .h file.
Edit: I added a more complete example
class ClassB
{
public:
ClassB(int comPort);
private:
int m_comPort;
};
ClassB::ClassB(int comPort) :
m_comPort(comPort)
{
}
class ClassA
{
public:
ClassA();
private:
const int comPort;
ClassB B;
};
ClassA::ClassA() :
comPort(5),
B(comPort)
{
}
int main()
{
ClassA A;
return 0;
}
Because the object is initialised before comPort is fully initialised, the value for comPort is garbage.
What would be the correct way to circumvent this? I can think of the following:
Initialise the const int in the header file
Create and initialise the object in the body of the constructor
use a #define
It seems like a problem with the order your members are initialized. Class members are initialized in the order they are declared. The order they are initialized in the constructor does not override this. In the next example bar::my_foo is initialized before bar::my_const, which will cause problems. my_foo will be initialized with an unitialized my_const member;
struct foo {
foo(int p_x) : x(p_x) {}
int x;
}
struct bar {
bar() : my_const(5), my_foo(my_const) {}
foo my_foo;
const int my_const;
}
The problem can be fixed by changing order the members are declared.
struct bar {
bar() : my_const(5), my_foo(my_const) {}
const int my_const; // my_const before my_foo
foo my_foo;
}
You can reproduce your error if you exchange declaration of comPort and B in definition of ClassA. See this comment on SO concerning Constructor initialization-list evaluation order.
Hence, make sure that if an initializer list relies on a specific order of evaluation, then the declaration of the members to be initialized must adhere to this order.
I have a class where the constructor receives an integer:
class One
{
public:
One(int i)
{
foo(i);
}
void foo(int i)
{
// Do something with i
}
};
The above compiles fine.
I have a second class that has a member of type One. Compiling this results in an error where I pass the int (the error is "expected a type specifier"):
class Two
{
public:
One x(1);
};
I can, however, initialize the member if it is a pointer:
class Three
{
public:
One *x = new One(1);
};
Can I initialize the class without using a pointer?
Thanks!
With:
class Two
{
public:
One x(1);
};
and based on language rules, the compiler attempts to parse x as a member function returning an object of type One, but rather than seeing valid parameter-declarations which requires at least a list of 0 or more type-specifiers, it sees a non-type.
class Three
{
public:
One *x = new One(1);
};
Can I initialize the class without using a pointer?
Yes, use the uniform-brace-initialization syntax for value-initialization:
class Three
{
public:
One x{1};
};
Or copy-initialization:
class Three
{
public:
One x = 1; //Uses converting constructor,
//see http://en.cppreference.com/w/cpp/language/converting_constructor
//or
One x = One(your, multiple, arguments, here);
};
Or member-initializer-lists in the Constructor:
class Three
{
public:
Three(...) : x(1) { ... }
One x;
...
};
One x(1);
is parsed as a function declaration, that is why it expects a type in parentheses. You can use
One x = 1;
or
One x{1};
instead.
Based on this question (asked a while ago)
inline-object-instantiation-and-transformation-in-java
Is there a way to instantiate and object and initialize it's members in a single line of c++, without the use of a constructor?
In java, as per the link:
JFrame aFrame = new JFrame();
aFrame.add(new JPanel() {{
setSize(100,100);
setLocation(50,50);
setBackground(Color.red);
}});
Can this be done in any way in c++?
EDIT: For example
class Foo{
public:
int test;
int test2;
};
int main(){
Foo foo(){{test=5 test2=4}}; //Like this
}
If the class is an aggregate (with no base classes, non-public members, virtual functions or user-declared constuctors), then you can use aggregate initialisation to initialise its members:
struct thing {
int a,b,c;
};
thing t = {1,2,3};
Otherwise, it can only be initialised by a constructor.
There's one idiom that allows syntax similar to Java. As with everything, it has its downsides as well. I'll leave it up to you to figure out whether it's right for this.
class Foo {
int a;
int b;
int c;
public:
Foo &setA(int val) {a = val; return *this;}
Foo &setB(int val) {b = val; return *this;}
Foo &setC(int val) {c = val; return *this;}
};
Now you can do the following:
auto foo = Foo().setB(2).setA(1).setC(3);
You can apply it to as many or few members as desired. However, it can be tricky in some cases to ensure you always have a valid object. Required initialization can go in the constructor.
Something along these lines that might be more natural is Boost.Parameter, which offers named parameter support that you can use to combine meaningful names with constructor arguments.
That is not an anonymous class. An anonymous class is one without a name.
If you want an anonymous (temporary) instance, and you can initialize it like so:
struct Foo {
int a;
int b;
};
void bar(Foo const &);
int main() {
bar(Foo{1,2});
}
See Mike's answer for the equivalent for a named instance of the named structure. The aggregate constraint is the same.