In C# const implies static so you can reference a public const without having to reference an instance of a class or struct. In C++ this is not the case. If you want to access a const member variable in C++ you need to first have a reference to an instance of the class. In C++ as far as I can tell making a member variable const causes its data to be either replaced with an literal value or stored in the text or data segment (depending on the compiler) of the program. So my question is, if const member variables are allocated only once for a given class (not per instance) and stored in an area separate from instance specific member data, why can't you access a public const class member variable without a reference to an instance of the class such as:
struct Example {
const int array[] = {1, 2, 3};
};
void main() {
std::cout << Example::array[1];
}
Instead you need to make them a static const and initialize them outside of the class such as:
struct Example {
static const int array[3];
};
const int Example::array[3] = {1, 2, 3}
void main() {
std::cout << Example::array[1];
}
Just because the member is const does not imply that it has the same value in all instances. Consider:
struct foo {
const int x = 1;
foo(int a) : x(a) {}
};
foo a{1};
foo b{2};
Now a and b have different values for their const int member. I don't know C# but it looks like something is missing when you cannot have const non-static
members. On the other hand const members come with some downsides in C++ and the easiest is to avoid them completely in favor of encapsulation (when there is no setter and the member is never modified within the class, it is essentially constant).
Note that even though there is a default initializer for the member = 1; this does not imply that all instances have the same value for x. Default initializers only apply when a constructor does not provide an initializer in its member initialization list, but in the above example it does so.
Related
As reported in this Q&A, const static member functions are/were not available in C++. Did anything change since then (2011)?
Is there another way to have static member functions that do not modify the static members of their class?
Something like (pseudo-code):
class C
{
static int a;
public:
static void Incr() { ++a; }
static int Ret() const { return a; }
};
int C::a = 0;
I would need to call a [const] static member function from another class' const member function.
According to the current cppreference.com (page about static members), static member functions still cannot be const, because the const keyword only modifies the this pointer, which static functions obviously do not have.
So nothing seems to have changed since the answer you were referring to was written.
Did anything change since then (2011)?
Nothing changed, you still can't cv-qualify a static member function.
Is there another way to have static member functions that do not modify the static members of their class?
Not a perfect solution, but you may declare const "aliases" to static data members:
static int Ret() {
static constexpr const auto& a = C::a;
// Now C::a is shadowed by the local a
// and the function can't modify it.
// a = 2; // ill-formed
return a * 2; // OK
}
It still requires discipline, but at least that way a compiler can catch unintended modification attempts.
Class which has only static fields and static methods doesn't deserve to be called class. It is just form of functions and global variables with fancy name spacing.
Anyway IMO it is much better to have a regular class with regular fields and methods and then instantiate it as a global variable (not very nice solution, but at least more honest where class contains only static fields and methods).
class C
{
int a;
public:
C() : a(0) {}
void Incr() { ++a; }
int Ret() const { return a; }
};
C instance;
Or use singleton pattern which I hate.
From generated code perspective there should be no difference.
This question already has answers here:
Why can I call a non-const member function pointer from a const method?
(5 answers)
Closed 3 years ago.
Imagine the following example:
class A
{
public:
void doSomeStuff() { std::cout << "SomeStuff" << std::endl; }
};
class B
{
public:
B(A& a) : a(a) {}
void constStuff() const { a.doSomeStuff(); }
private:
A &a;
};
If doSomeStuff() would change the data, wouldn't that affect class B as well? Why is such behaviour allowed?
If doSomeStuff() would change the data, wouldn't that affect class B as well?
Well, not in the way a compiler checks for const correctness. A B holds a reference to an A. That object can reside anywhere, but most importantly it doesn't reside inside the B object. So modifying it does not do something with undefined behavior like changing a const object. We have a reference to a non-const object, so it's possible to modify the object via the reference. That's as far as the C++ type system cares, whether or not the object is maybe physically const.
It will probably affect the logical state of the B, but it is the responsibility of the programmer to ensure the class invariants hold. C++ will not hold your hand in that endeavor.
The original object of the class A will be changed.
When you are using a const member function then the function deals with const T *this where T is the class type.
That is data members of the object are considered constant.
For a referenced type it could look like
A & const a;
However references themselves can not be constant.
That is for example this declaration
int x;
int & const rx = x;
is invalid and does not mean the same as
const int & rx = x;
So the class B has a reference that points to a non-constant object and using the reference the object can be changed.
Compare with the following declaration of the class B
class B
{
public:
B(A * a) : a(a) {}
void constStuff() const { a.doSomeStuff(); }
private:
A *a;
};
Then then a constant member function is used the data member is considered like
A * const a;
(pointers themselves may be constant) that is the pointer itself that is constant not the object pointed to by the pointer and you can not change the pointer itself but you can change the object pointed to by the pointer.
The const-qualified this pointer that's present in a const-method protects data changes from members inside B. B holds a reference to A so the object a references does not reside inside B and thus changes are allowed. This const qualification of this does not pass on to the reference.
If you would want to avoid that, you're supposed to make the reference to the helper class const:
class B
{
public:
B(const A& a) : a(a) {}
void constStuff() const { /* Invalid call: a.doSomeStuff(); */ }
private:
const A &a;
};
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;
};
For a code like this:
class foo {
protected:
int a;
public:
class bar {
public:
int getA() {return a;} // ERROR
};
foo()
: a (p->param)
};
I get this error:
invalid use of non-static data member 'foo::a'
currently the variable a is initialized in the constructor of foo.
if I make it static, then it says:
error: 'int foo::a' is a static data member; it can only be initialized at its definition
However I want to pass a value to a in the constructor.
What is the solution then?
In C++, unlike (say) Java, an instance of a nested class doesn't intrinsically belong to any instance of the enclosing class. So bar::getA doesn't have any specific instance of foo whose a it can be returning. I'm guessing that what you want is something like:
class bar {
private:
foo * const owner;
public:
bar(foo & owner) : owner(&owner) { }
int getA() {return owner->a;}
};
But even for this you may have to make some changes, because in versions of C++ before C++11, unlike (again, say) Java, a nested class has no special access to its enclosing class, so it can't see the protected member a. This will depend on your compiler version. (Hat-tip to Ken Wayne VanderLinde for pointing out that C++11 has changed this.)
In C++, nested classes are not connected to any instance of the outer class. If you want bar to access non-static members of foo, then bar needs to have access to an instance of foo. Maybe something like:
class bar {
public:
int getA(foo & f ) {return foo.a;}
};
Or maybe
class bar {
private:
foo & f;
public:
bar(foo & g)
: f(g)
{
}
int getA() { return f.a; }
};
In any case, you need to explicitly make sure you have access to an instance of foo.
The nested class doesn't know about the outer class, and protected doesn't help. You'll have to pass some actual reference to objects of the nested class type. You could store a foo*, but perhaps a reference to the integer is enough:
class Outer
{
int n;
public:
class Inner
{
int & a;
public:
Inner(int & b) : a(b) { }
int & get() { return a; }
};
// ... for example:
Inner inn;
Outer() : inn(n) { }
};
Now you can instantiate inner classes like Inner i(n); and call i.get().
You try to access private member of one class from another. The fact that bar-class is declared within foo-class means that bar in visible only inside foo class, but that is still other class.
And what is p->param?
Actually, it isn't clear what do you want to do
Your Question is not clear but there is use case when you will get this issue .
Invalid use of non-static data member.
When you are using "non-static data member in another class try to not use with scope resolution operator
Example::className::memberData = assignivalue ;
instead of above try to use object of className class;
Example:: m_pClassName->memberData=assignValue;*
Internally and about the generated code, is there a really difference between :
MyClass::MyClass(): _capacity(15), _data(NULL), _len(0)
{
}
and
MyClass::MyClass()
{
_capacity=15;
_data=NULL;
_len=0
}
thanks...
You need to use initialization list to initialize constant members,references and base class
When you need to initialize constant member, references and pass parameters to base class constructors, as mentioned in comments, you need to use initialization list.
struct aa
{
int i;
const int ci; // constant member
aa() : i(0) {} // will fail, constant member not initialized
};
struct aa
{
int i;
const int ci;
aa() : i(0) { ci = 3;} // will fail, ci is constant
};
struct aa
{
int i;
const int ci;
aa() : i(0), ci(3) {} // works
};
Example (non exhaustive) class/struct contains reference:
struct bb {};
struct aa
{
bb& rb;
aa(bb& b ) : rb(b) {}
};
// usage:
bb b;
aa a(b);
And example of initializing base class that requires a parameter (e.g. no default constructor):
struct bb {};
struct dd
{
char c;
dd(char x) : c(x) {}
};
struct aa : dd
{
bb& rb;
aa(bb& b ) : dd('a'), rb(b) {}
};
Assuming that those values are primitive types, then no, there's no difference. Initialization lists only make a difference when you have objects as members, since instead of using default initialization followed by assignment, the initialization list lets you initialize the object to its final value. This can actually be noticeably faster.
Yes. In the first case you can declare _capacity, _data and _len as constants:
class MyClass
{
private:
const int _capacity;
const void *_data;
const int _len;
// ...
};
This would be important if you want to ensure const-ness of these instance variables while computing their values at runtime, for example:
MyClass::MyClass() :
_capacity(someMethod()),
_data(someOtherMethod()),
_len(yetAnotherMethod())
{
}
const instances must be initialized in the initializer list or the underlying types must provide public parameterless constructors (which primitive types do).
I think this link http://www.cplusplus.com/forum/articles/17820/ gives an excellent explanation - especially for those new to C++.
The reason why intialiser lists are more efficient is that within the constructor body, only assignments take place, not initialisation. So if you are dealing with a non-built-in type, the default constructor for that object has already been called before the body of the constructor has been entered. Inside the constructor body, you are assigning a value to that object.
In effect, this is a call to the default constructor followed by a call to the copy-assignment operator. The initialiser list allows you to call the copy constructor directly, and this can sometimes be significantly faster (recall that the initialiser list is before the body of the constructor)
I'll add that if you have members of class type with no default constructor available, initialization is the only way to construct your class.
A big difference is that the assignment can initialize members of a parent class; the initializer only works on members declared at the current class scope.
Depends on the types involved. The difference is similar between
std::string a;
a = "hai";
and
std::string a("hai");
where the second form is initialization list- that is, it makes a difference if the type requires constructor arguments or is more efficient with constructor arguments.
The real difference boils down to how the gcc compiler generate machine code and lay down the memory. Explain:
(phase1) Before the init body (including the init list): the compiler allocate required memory for the class. The class is alive already!
(phase2) In the init body: since the memory is allocated, every assignment now indicates an operation on the already exiting/'initialized' variable.
There are certainly other ways to handle const type members. But to ease their life, the gcc compiler writers decide to set up some rules
const type members must be initialized before the init body.
After phase1, any write operation only valid for non-constant members.
There is only one way to initialize base class instances and non-static member variables and that is using the initializer list.
If you don't specify a base or non-static member variable in your constructor's initializer list then that member or base will either be default-initialized (if the member/base is a non-POD class type or array of non-POD class types) or left uninitialized otherwise.
Once the constructor body is entered, all bases or members will have been initialized or left uninitialized (i.e. they will have an indeterminate value). There is no opportunity in the constructor body to influence how they should be initialized.
You may be able to assign new values to members in the constructor body but it is not possible to assign to const members or members of class type which have been made non-assignable and it is not possible to rebind references.
For built in types and some user-defined types, assigning in the constructor body may have exactly the same effect as initializing with the same value in the initializer list.
If you fail to name a member or base in an initializer list and that entity is a reference, has class type with no accessible user-declared default constructor, is const qualified and has POD type or is a POD class type or array of POD class type containing a const qualified member (directly or indirectly) then the program is ill-formed.
If you write an initializer list, you do all in one step; if you don't write an initilizer list, you'll do 2 steps: one for declaration and one for asign the value.
There is a difference between initialization list and initialization statement in a constructor.
Let's consider below code:
#include <initializer_list>
#include <iostream>
#include <algorithm>
#include <numeric>
class MyBase {
public:
MyBase() {
std::cout << __FUNCTION__ << std::endl;
}
};
class MyClass : public MyBase {
public:
MyClass::MyClass() : _capacity( 15 ), _data( NULL ), _len( 0 ) {
std::cout << __FUNCTION__ << std::endl;
}
private:
int _capacity;
int* _data;
int _len;
};
class MyClass2 : public MyBase {
public:
MyClass2::MyClass2() {
std::cout << __FUNCTION__ << std::endl;
_capacity = 15;
_data = NULL;
_len = 0;
}
private:
int _capacity;
int* _data;
int _len;
};
int main() {
MyClass c;
MyClass2 d;
return 0;
}
When MyClass is used, all the members will be initialized before the first statement in a constructor executed.
But, when MyClass2 is used, all the members are not initialized when the first statement in a constructor executed.
In later case, there may be regression problem when someone added some code in a constructor before a certain member is initialized.
Here is a point that I did not see others refer to it:
class temp{
public:
temp(int var);
};
The temp class does not have a default ctor. When we use it in another class as follow:
class mainClass{
public:
mainClass(){}
private:
int a;
temp obj;
};
the code will not compile, cause the compiler does not know how to initialize obj, cause it has just an explicit ctor which receives an int value, so we have to change the ctor as follow:
mainClass(int sth):obj(sth){}
So, it is not just about const and references!