How to access static members of a class? - c++

I am starting to learn C++ and Qt, but sometimes the simplest code that I paste from a book results in errors.
I'm using g++4.4.2 on Ubuntu 10.04 with QtCreator IDE. Is there a difference between the g++ compiler syntax and other compilers? For example when I try to access static members something always goes wrong.
#include <iostream>
using namespace std;
class A
{
public:
static int x;
static int getX() {return x;}
};
int main()
{
int A::x = 100; // error: invalid use of qualified-name 'A::x'
cout<<A::getX(); // error: : undefined reference to 'A::x'
return 0;
}
I think it's exactly the same as declared here and here (isn't it?). So what's wrong with the above code?

You've declared the static members fine, but not defined them anywhere.
Basically what you've said "there exists some static member", but never set aside some memory for it, you need:
int A::x = 100;
Somewhere outside the class and not inside main.

Section [9.4.2]
Static Data Members
The declaration of a static data member in its class definition is not a definition and may be of an incomplete type other than cv-qualified void. The definition for a static data member shall appear in a namespace scope enclosing the member’s class definition. In the definition at namespace scope, the name of the static data member shall be qualified by its class name using the :: operator

You need to define the static member variable of the class outside the class as static member variables require declaration as well as definition.
#include <iostream>
using namespace std;
class A
{
public:
static int x;
static int getX() {return x;}
};
int A::x; // STATIC MEMBER VARIABLE x DEFINITION
int main()
{
A::x = 100; // REMOVE int FROM HERE
cout<<A::getX();
return 0;
}

Try:
#include <iostream>
using namespace std;
class A
{
public:
// This declares it.
static int x;
static int getX(){return x;}
};
// Now you need an create the object so
// This must be done in once source file (at file scope level)
int A::x = 100;
int main()
{
A::x = 200;
// Notice no 'int' keyword before A::x on this line. You can modify A::x
cout<<A::getX(); // Should work
return 0;
}

The definition of static member variables must live at file scope, i.e. outside all functions, etc.

Try this example:
#include<iostream>
using namespace std;
class check
{
static int a;
public:
void change();
} ;
int check::a=10;
void check::change()
{
a++;
cout<<a<<"\n";
}
int main()
{
int i,j;
check c;
check b;
c.change();
b.change();
return 0;
}

Now you have worked out how to use static class members I will advise you that you should generally use them only in the following circumstances:
For use in templates. So in your example you could have GetX() in different classes and in a template somewhere you would use
template< typename T >
int func()
{
return T::GetX();
}
although obviously more elaborate. But here your static function being in a class serves a purpose.
Where the function needs access to the class, i.e. to private members. You could make it a friend but you may as well make it static. Often the case in callbacks.
The rest of the time you can probably use compilation-unit level functions and variables which has the advantage of taking your members out of the header (particularly if they are private). The less implementation detail you give the better.

You can use the inline keyword since c++ 17 in front of static members to avoid a definition outside of class scope. Your code should now look like this:
#include <iostream>
using namespace std;
class A
{
public:
inline static int x;
static int getX() {return x;}
};
int main()
{
A::x = 100; //Works now
cout<<A::getX()<<'\n';
return 0;
}

Case 1: static variable
As we all know, defining a static variable inside a class which will throw compilation error. E.g. below
class Stats
{
public:
static int AtkStats[3];
*static int a =20;* // Error: defining a value for static variable
};
int Stats::AtkStats[3] = {10, 0, 0};
Output:
error: ISO C++ forbids in-class initialization of non-const static member 'Stats::a'
Case 2: const static variable
For const static variable, we can define a value either inside a class or Outside class.
class Stats
{
public:
static const int AtkStats[3];
static const int a =20; // Success: defining a value for a const static
};
const int Stats::AtkStats[3] = {10, 0, 0};
const int Stats::a = 20; // we can define outside also
Output:
Compilation success.

Related

Why can I not set a value for static variable inside the class?

I am new to c++ and experimenting with classes and static variables.
I have found the solution to making the code run but I am not sure why this works and why my previous method did not
#include <iostream>
using namespace std;
class Person {
static int id;
public:
void createPerson() {
id++;
cout << id << endl;
}
};
int Person::id = 0;
int main() {
Person Person1;
Person Person2;
Person1.createPerson();
Person2.createPerson();
}
I am wondering why I must declare the value of id outside the class. And why I cannot have something like..
class Person {
static int id = 0;
public:
void createPerson() {
id++;
cout << id << endl;
}
};
static data members are not parts of objects, so you need to tell the compiler explicitly in which translation unit to store them by providing that definition.
Note that static data members of class templates can be defined in the header files.
In C++17 a static data member can be declared as inline, so that no out-of-line definition is necessary.
Adding the inline keyword will do the job. Simply change your line to:
static inline int id = 0;
Another possibility would be, but only if your value is constant, to declare it like this:
static inline constexpr int id = 0;
This is the preferred way for declaring global constants instead of using #defines.
Within a class definition static data members are declared bur not defined. So you may even to use a non-complete type in a declaration of a static data member inside a class definition.
For example
struct A
{
static int a[];
};
int A::a[10];
Here in this example the declaration of the data member a within the class definition has an incomplete array type (the number of elements of the array is unknown).
Starting from C++ 17 you may declare a static data member as an inline member. For example
class Person {
inline static int id = 0;
public:
void createPerson() {
id++;
cout << id << endl;
}
};
In this case you may initialize it in the declaration inside the class definition.
Otherwise you may initialize a static data member within a class definition only if it is declared as having an integral type and has the qualifier const or the specifier constexpr (in the last case the static data member will be an inline declaration).
But if a static data member is declared as a const object nevertheless you have to define it outside the class if for example you will try to get the address of the static data member. For example this code is invalid
#include <iostream>
using namespace std;
class Person {
const static int id = 0;
public:
void createPerson() {
cout << &id << endl;
}
};
int main()
{
Person Person1;
Person Person2;
Person1.createPerson();
Person2.createPerson();
}
As there is the address of the static data member is taken then you have to define the static data member.
#include <iostream>
using namespace std;
class Person {
const static int id = 0;
public:
void createPerson() {
cout << &id << endl;
}
};
const int Person::id;
int main()
{
Person Person1;
Person Person2;
Person1.createPerson();
Person2.createPerson();
}
This program will compile.

C++ const static member is not identified when trying to use it to initialize an array

I want to create a constant static int variable to specify the range of an array. I'm running into problems and getting errors saying that the variable is not a member of the class, but I can print out the variable in main using ClassName::staticVarName.
I cannot figure out how to properly set up a static variable that belongs to a class so that it can be used to initialize an array. The variable prints in main, but for some reason it will not compile when I try to use it to define a classes's array field's range.
error: class "RisingSunPuzzle" has no member "rows"
error: class "RisingSunPuzzle" has no member "cols"
header file for class:
#pragma once
#include<map>
#include<string>
#include<memory>
class RisingSunPuzzle
{
private:
bool board[RisingSunPuzzle::rows][RisingSunPuzzle::cols];
public:
RisingSunPuzzle();
~RisingSunPuzzle();
static const int cols;
static const int rows;
void solvePuzzle();
void clearboard();
};
cpp file for class:
#include "RisingSunPuzzle.h"
const int RisingSunPuzzle::cols = 5;
const int RisingSunPuzzle::rows = 4;
RisingSunPuzzle::RisingSunPuzzle()
{
}
RisingSunPuzzle::~RisingSunPuzzle()
{
}
void RisingSunPuzzle::solvePuzzle()
{
}
void RisingSunPuzzle::clearboard()
{
}
The names of data members that are referred to must be declared before the data members that refer them to.
Also the static constants have to be initializes.
You can reformat the class the following way
class RisingSunPuzzle
{
public:
static const int cols = 5;
static const int rows = 4;
private:
bool board[RisingSunPuzzle::rows][RisingSunPuzzle::cols];
public:
RisingSunPuzzle();
~RisingSunPuzzle();
void solvePuzzle();
void clearboard();
};
//...
There is no need to define the constants if they are not ODR used. Nevertheless you can define them (without initializers) like
const int RisingSunPuzzle::cols;
const int RisingSunPuzzle::rows;

Initialize static variables declared in header

I'm changing the class implementation of a large class for a company project that has several static variables declared as private members of the class. There are many arrays and structs declared in the class header that utilize these static variables. I now need to assign the static data members values from my main function somehow. I tried assigning the static variables through the constructor but the header is declared prior to the constructor call so that wasn't possible.
For example, if I have
class Data
{
private:
static unsigned int numReadings = 10;
static unsigned int numMeters = 4;
unsigned int array[numMeters];
}
I would want to change it such that I could set numReadings and numMeters from my main function somehow, so it will allow all of my arrays and structs that utilize numMeters and numReadings to be initialized properly.
Is there a way to do this in C++? Of course I could always change my class design and set these in the constructor somehow but I'd like to avoid that if I can as it will take quite a long time.
You cannot do it in the main function, but you can do it in the main.cpp file:
// Main.cpp
#include <iostream>
#include "T.h"
using namespace std;
int T::a = 0xff;
int main()
{
T t; // Prints 255
return 0;
}
// T.h
#pragma once
#include <iostream>
using namespace std;
class T {
public:
T() { cout << a << endl; }
private:
static int a;
};
Have you tried making them public and accessing them with Data::numReadings = 10?
UPDATE:
#include <cstdlib>
using namespace std;
/* * */
class Asdf
{
public:
static int a;
};
int Asdf::a = 0;
int main(int argc, char** argv) {
Asdf::a = 2;
return 0;
}
Regardless of the accessibility of these variables, you need to define and initialize the static members outside the class definition:
// header
class Data
{
private:
static unsigned int numReadings;
static unsigned int numMeters;
unsigned int array[numMeters]; //<=see edit
};
// class implementation file
unsigned int Data::numReadings = 10;
unsigned int Data::numMeters = 4;
This is part of the implementation of the class and shouldn't be in the header (ODR rule).
Of course, if you want to access these variables (which are shared among all instances of the class) from outside, you need to make them public, or better, foresee and accessor.
Edit:
As the question is formulated around the static issue, I didn't notice the variable length array : this is not standard c++, although some compilers might accept it as a non-standard extension.
To do this properly, you should define a vector and initialize it at construction:
class Data
{
public:
Data ();
private:
static unsigned int numReadings;
static unsigned int numMeters;
vector<unsigned int> mycontainer; //<=for dynamic size
};
Data::Data() : mycontainer(numMeters) { } // initialize object with right size

Can't call a static method in Qt

I have a simple class containing a static attribute. There are two static methods in this class: one to get the static attribute and the other to initialize it. Yet when call the static method the compiler reports an error.
The class:
class Sudoku {
Cell Grid[9][9];
int CurrentLine;
int CurrentColumn;
void deleteValInColumn(int val, int col);
void deleteValInRow(int val, int row);
void deleteValInBox(int val, int x, int y);
static int unsetted; //!
public:
static void IniUnsetted() { //!
unsetted = 0;
}
static int GetUns() { //!
return unsetted;
}
Sudoku(ini InitGrid[9][9]);
void Calculate_Prob_Values();
Cell getCell(int x, int y);
QVector<int> getPossibleValues(int x, int y);
bool SolveIt();
};
This is the error I get:
In member function 'bool Sudoku::SolveIt()':
no return statement in function returning non-void [-Wreturn-type]
In function `ZN6Sudoku6GetUnsEv':
undefined reference to `Sudoku::unsetted` error: ld returned 1 exit status
You will need to define the static variable, even if it is not initialized explicitly. That is what is missing in your code. You should have provided a simple example to reproduce the issue, but for your convenience I am providing one which works.
main.cpp
class Foo {
public:
static int si;
static void bar();
};
int Foo::si = 0; // By default, it will be initialized to zero though.
void Foo::bar() {
Foo::si = 10;
};
int main()
{
Foo::bar();
return 0;
}
Note: I would suggest to get someone to review your code because "unsetted" is incorrect English. If we are at it, you would probably need to fix your indentation as well.
In your code there is no definition of unsetted, there is only declaration.
The solution is to put somewhere in your cpp file a line like this:
int Sudoku::unsetted
The reason for that is that each instantiation of Sudoku class will use the same unsetted member so it cannot be defined for each of them, so it's up to programmer to define it in one place only.
In your cpp file, define the static variable (ideally with an initialization):
int Sudoku::unsetted = 0;
If you are declaring any static variable in class, then you should define that variable outside the class also.
Example:
class A
{
public:
static int x; // declaration
};
int A::x; // definition

Pointer to static member variable [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
C++: undefined reference to static class member
The following C++ code compiles well (using g++ -c) but it doesn't link giving the error: undefined reference toAbc::X'`
#include <iostream>
using namespace std;
class Abc {
public:
const static int X = 99;
};
int main()
{
Abc a1;
cout << &(Abc::X) << endl;
}
I want to know why this is not allowed?
You need to have that static member actually defined, not just declared...
Add this line before your main():
const int Abc::X = 99;
As of C++17 you can also do an inline static, in which case the above additional line of code in a .cpp file is not needed:
class Abc {
public:
inline const static int X = 99; // <-- "inline"
};
If the static member is used in a way which requires an lvalue (i.e. in a way that requires it to have an address) then it must have a definition. See the explanation at the GCC wiki, which includes references to the standard and how to fix it.
If you don't like to think about translation units, static initialization order and stuff like that, just change your static constants into methods.
#include <iostream>
using namespace std;
class Abc {
public:
inline static const int& X(){
static int x=99;
return x;
}
};
int main()
{
// Abc a1;
cout << &(Abc::X()) << endl;
}