Class declaration in a header file and static variables - c++

Noob question, but would like to understand the following:
Imagine I have a multifile project. I'm specifying a class in a header file to be shared among all the files in the project, and I write this : static int test = 0; and in the next line this: static const int MAX = 4;
The first one would be an error trying to compile because of the one definition rule. But the second one will compile without errors. Why?
From what I understand, both have the same properties: whole execution storage duration, class scope and no linkage.
Any help?
EDIT: testing an external constant declaration in a header: extern const int MAX = 4; to force external linkage produced the expected error. So I don't understand why with the variable it gives me the error and with the constant it doesn't.

Try
static const int test = 0;
I've sometimes noticed compiler errors with the immediate initialization of static const variables in the header file. You can always use the declaration in the header
class MyClass
{
// ...
static const int test;
// ...
}
and initialize it in the corresponding .cpp file
const int MyClass::test = 0;
This should work properly with any other types than int as well.

Integer constants in C++ don't actually occupy any space in the object and don't act like variables in general. Think about them more like numbers that are given names in this particular context.

Related

C++ error: fields must have a constant size

can someone please give me a hint how to solve the following problem:
clang++-7 -pthread -std=c++17 -o main createLibrary/configuration.cpp createLibrary/growbox.cpp createLibrary/helper.cpp createLibrary/httprequests.cpp main.cpp
In file included from createLibrary/configuration.cpp:2:
In file included from createLibrary/configuration.h:1:
In file included from createLibrary/growbox.h:12:
createLibrary/httprequests.h:13:10: error: fields must have a constant size:
'variable length array in structure' extension will never be supported
char device[configuration::maxNameSize];
^
1 error generated.
I'm including the .h files in the order configuration.h, httprequests.h. I want all necessary config-parameters to be configured in the configuration.cpp file, but I got the displayed error. What am I doing wrong here?
configuration.h
extern int const maxNameSize;
configuration.cpp
int const configuration::maxNameSize = 30;
httprequests.h
char device[configuration::maxNameSize];
httprequests.cpp
char HTTPREQUESTS::device[configuration::maxNameSize];
An extern const int is not a constant expression.
a variable is usable in constant expressions at a point P if
the variable is
a constexpr variable, or
it is a constant-initialized variable
of reference type or
of const-qualified integral or enumeration type
and the definition of the variable is reachable from P
and
P is in the same translation unit as the definition of the variable
(emphasis added)
I want all necessary config-parameters to be configured in the
configuration.cpp file
You are out of luck. The value of maxNameSize must be visible to it's compile-time users.
Declare maxNameSize like this
// configuration.h
class configuration
{
public:
static const int maxNameSize = 30;
...
};
And no need to define it in configuration.cpp.
Your way doesn't make maxNamesize a compile time constant.
EDIT, I am assuming that configuration is a class. If it's a namespace then do the following instead
// configuration.h
namespace configuration
{
const int maxNamesize = 30;
...
}
Constants are an exception to the one definition rule, so it's OK to define them in a header file.
What am I doing wrong here?
You have defined an array variable with size that is not compile time constant.
Solution: You can either
Define the variable in the same translation unit where you use it as the size of an array so that it may be compile time constant. Given that the array is in a header, which presumably is included into multiple translation units, the size cannot be defined externally. It has to be either static or inline.
Or use a dynamic array instead. Simplest way to create dynamic array is to use std::vector.

Why the singleton initialization failed (link error) [duplicate]

Very simply put:
I have a class that consists mostly of static public members, so I can group similar functions together that still have to be called from other classes/functions.
Anyway, I have defined two static unsigned char variables in my class public scope, when I try to modify these values in the same class' constructor, I am getting an "unresolved external symbol" error at compilation.
class test
{
public:
static unsigned char X;
static unsigned char Y;
...
test();
};
test::test()
{
X = 1;
Y = 2;
}
I'm new to C++ so go easy on me. Why can't I do this?
If you are using C++ 17 you can just use the inline specifier (see https://stackoverflow.com/a/11711082/55721)
If using older versions of the C++ standard, you must add the definitions to match your declarations of X and Y
unsigned char test::X;
unsigned char test::Y;
somewhere. You might want to also initialize a static member
unsigned char test::X = 4;
and again, you do that in the definition (usually in a CXX file) not in the declaration (which is often in a .H file)
Static data members declarations in the class declaration are not definition of them.
To define them you should do this in the .CPP file to avoid duplicated symbols.
The only data you can declare and define is integral static constants.
(Values of enums can be used as constant values as well)
You might want to rewrite your code as:
class test {
public:
const static unsigned char X = 1;
const static unsigned char Y = 2;
...
test();
};
test::test() {
}
If you want to have ability to modify you static variables (in other words when it is inappropriate to declare them as const), you can separate you code between .H and .CPP in the following way:
.H :
class test {
public:
static unsigned char X;
static unsigned char Y;
...
test();
};
.CPP :
unsigned char test::X = 1;
unsigned char test::Y = 2;
test::test()
{
// constructor is empty.
// We don't initialize static data member here,
// because static data initialization will happen on every constructor call.
}
in my case, I declared one static variable in .h file, like
//myClass.h
class myClass
{
static int m_nMyVar;
static void myFunc();
}
and in myClass.cpp, I tried to use this m_nMyVar. It got LINK error like:
error LNK2001: unresolved external symbol "public: static class...
The link error related cpp file looks like:
//myClass.cpp
void myClass::myFunc()
{
myClass::m_nMyVar = 123; //I tried to use this m_nMyVar here and got link error
}
So I add below code on the top of myClass.cpp
//myClass.cpp
int myClass::m_nMyVar; //it seems redefine m_nMyVar, but it works well
void myClass::myFunc()
{
myClass::m_nMyVar = 123; //I tried to use this m_nMyVar here and got link error
}
then LNK2001 is gone.
Since this is the first SO thread that seemed to come up for me when searching for "unresolved externals with static const members" in general, I'll leave another hint to solve one problem with unresolved externals here:
For me, the thing that I forgot was to mark my class definition __declspec(dllexport), and when called from another class (outside that class's dll's boundaries), I of course got the my unresolved external error.
Still, easy to forget when you're changing an internal helper class to a one accessible from elsewhere, so if you're working in a dynamically linked project, you might as well check that, too.
When we declare a static variable in a class, it is shared by all the objects of that class. As static variables are initialized only once they are never initialized by a constructor. Instead, the static variable should be explicitly initialized outside the class only once using the scope resolution operator (::).
In the below example, static variable counter is a member of the class Demo. Note how it is initialized explicitly outside the class with the initial value = 0.
#include <iostream>
#include <string>
using namespace std;
class Demo{
int var;
static int counter;
public:
Demo(int var):var(var){
cout<<"Counter = "<<counter<<endl;
counter++;
}
};
int Demo::counter = 0; //static variable initialisation
int main()
{
Demo d(2), d1(10),d3(1);
}
Output:
Count = 0
Count = 1
Count = 2
In my case, I was using wrong linking.
It was managed c++ (cli) but with native exporting. I have added to linker -> input -> assembly link resource the dll of the library from which the function is exported. But native c++ linking requires .lib file to "see" implementations in cpp correctly, so for me helped to add the .lib file to linker -> input -> additional dependencies.
[Usually managed code does not use dll export and import, it uses references, but that was unique situation.]

Undefined reference C++

I have a file called Student.h which have the static integers in this way:
class Student
{
public:
static int _avrA,_avrB,_avrC,_avrD;
};
and I have university.h that inherits Student.h .
On the implementation of University.cpp , one of the functions returns:
return (_grade_average*(Student::_avrA/Student::_avrB))+7;
and the compiler writes:
undefined reference to Student::_avrA.
Do you know why it happens?
You have declared those variables, but you haven't defined them. So you've told the compiler "Somewhere I'm going to have a variable with this name, so when I use that name, don't wig out about undefined variables until you've looked everywhere for its definition."1
In a .cpp file, add the definitions:
int Student::_avrA; // _avrA is now 0*
int Student::_avrB = 1; // _avrB is now 1
int Student::_avrC = 0; // _avrC is now 0
int Student::_avrD = 2; // _avrD is now 2
Don't do this in a .h file because if you include it twice in two different .cpp files, you'll get multiple definition errors because the linker will see more than one file trying to create a variable named Student::_avrA, Student::_avbB, etc. and according to the One Definition to Rule Them All rule, that's illegal.
1 Much like a function prototype. In your code, it's as if you have a function prototype but no body.
* Because "Static integer members of classes are guaranteed to be initialised to zero in the absence of an explicit initialiser." (TonyK)
You have to define the static data members as well as declaring them. In your implementation Student.cpp, add the following definitions:
int Student::_avrA;
int Student::_avrB;
int Student::_avrC;
int Student::_avrD;

undefined reference error due to use of static variables [duplicate]

This question already has answers here:
static variable link error [duplicate]
(2 answers)
Closed 8 years ago.
I asked a question earlier today about singletons, and I'm having some difficulties understanding some errors I encountered. I have the following code:
Timing.h
class Timing {
public:
static Timing *GetInstance();
private:
Timing();
static Timing *_singleInstance;
};
Timing.cpp
#include "Timing.h"
static Timing *Timing::GetInstance() { //the first error
if (!_singleInstance) {
_singleInstance = new Timing(); //the second error
}
return _singleInstance;
}
There are two errors in this code which I can't figure out.
The method GetInstance() is declared in the header as static. Why in the cpp file do I have to omit the word static? It gives the error: "cannot declare member function ‘static Timing* Timing::GetInstance()’ to have static linkage". The correct way to write it is:
Timing *Timing::GetInstance() { ... }
Why can't I write _singleInstance = new Timing();? It gives the error: "undefined reference to Timing::_singleInstance". I solved this error by defining _singleInstance as a global var in the cpp file.
1: static means "local linkage" when used for a function declaration/definition outside a class-declaration.
Local linkage means that the particular function can only be referenced from code inside this particular file, and that doesn't make much sense with a method in a class.
2: Since your class declaration can be included multiple times, the actual storage for the static member should be defined in the cpp-file:
#include "Timing.h"
Timing* Timing::_singleInstance;
Timing *Timing::GetInstance() { //the first error
if (!_singleInstance) {
_singleInstance = new Timing(); //the second error
}
return _singleInstance;
}
Referencing to question 2: You need to specify the static variable at the top of your cpp-file:
Timing* Timing::_singleInstance = NULL;
static within a class means something completely different than static outside of it. Yeah, not the greatest design decision of C++, but, we have to live with it.
I imagine the whining comes from the linker, and it's because you have declared that variable but never defined it, making it an undefined references. Just add in your .cpp file a line like:
Timing* Timing::_singleInstance;
yes, you have to omit the static in the .cpp file
You'll have to 'reserve memory' for _singleInstance somewhere, e.g. by writing the following in the .cpp file:
Timing *Timing::_singleInstance = NULL;
(outside the definition of the member functions)
In the definition, you need to omit the static keyword. Its because that's teh syntax of C++. Nothing big.
Once you fix error number 1, error number 2 will be fixed automatically.

Unresolved external symbol on static class members

Very simply put:
I have a class that consists mostly of static public members, so I can group similar functions together that still have to be called from other classes/functions.
Anyway, I have defined two static unsigned char variables in my class public scope, when I try to modify these values in the same class' constructor, I am getting an "unresolved external symbol" error at compilation.
class test
{
public:
static unsigned char X;
static unsigned char Y;
...
test();
};
test::test()
{
X = 1;
Y = 2;
}
I'm new to C++ so go easy on me. Why can't I do this?
If you are using C++ 17 you can just use the inline specifier (see https://stackoverflow.com/a/11711082/55721)
If using older versions of the C++ standard, you must add the definitions to match your declarations of X and Y
unsigned char test::X;
unsigned char test::Y;
somewhere. You might want to also initialize a static member
unsigned char test::X = 4;
and again, you do that in the definition (usually in a CXX file) not in the declaration (which is often in a .H file)
Static data members declarations in the class declaration are not definition of them.
To define them you should do this in the .CPP file to avoid duplicated symbols.
The only data you can declare and define is integral static constants.
(Values of enums can be used as constant values as well)
You might want to rewrite your code as:
class test {
public:
const static unsigned char X = 1;
const static unsigned char Y = 2;
...
test();
};
test::test() {
}
If you want to have ability to modify you static variables (in other words when it is inappropriate to declare them as const), you can separate you code between .H and .CPP in the following way:
.H :
class test {
public:
static unsigned char X;
static unsigned char Y;
...
test();
};
.CPP :
unsigned char test::X = 1;
unsigned char test::Y = 2;
test::test()
{
// constructor is empty.
// We don't initialize static data member here,
// because static data initialization will happen on every constructor call.
}
in my case, I declared one static variable in .h file, like
//myClass.h
class myClass
{
static int m_nMyVar;
static void myFunc();
}
and in myClass.cpp, I tried to use this m_nMyVar. It got LINK error like:
error LNK2001: unresolved external symbol "public: static class...
The link error related cpp file looks like:
//myClass.cpp
void myClass::myFunc()
{
myClass::m_nMyVar = 123; //I tried to use this m_nMyVar here and got link error
}
So I add below code on the top of myClass.cpp
//myClass.cpp
int myClass::m_nMyVar; //it seems redefine m_nMyVar, but it works well
void myClass::myFunc()
{
myClass::m_nMyVar = 123; //I tried to use this m_nMyVar here and got link error
}
then LNK2001 is gone.
Since this is the first SO thread that seemed to come up for me when searching for "unresolved externals with static const members" in general, I'll leave another hint to solve one problem with unresolved externals here:
For me, the thing that I forgot was to mark my class definition __declspec(dllexport), and when called from another class (outside that class's dll's boundaries), I of course got the my unresolved external error.
Still, easy to forget when you're changing an internal helper class to a one accessible from elsewhere, so if you're working in a dynamically linked project, you might as well check that, too.
When we declare a static variable in a class, it is shared by all the objects of that class. As static variables are initialized only once they are never initialized by a constructor. Instead, the static variable should be explicitly initialized outside the class only once using the scope resolution operator (::).
In the below example, static variable counter is a member of the class Demo. Note how it is initialized explicitly outside the class with the initial value = 0.
#include <iostream>
#include <string>
using namespace std;
class Demo{
int var;
static int counter;
public:
Demo(int var):var(var){
cout<<"Counter = "<<counter<<endl;
counter++;
}
};
int Demo::counter = 0; //static variable initialisation
int main()
{
Demo d(2), d1(10),d3(1);
}
Output:
Count = 0
Count = 1
Count = 2
In my case, I was using wrong linking.
It was managed c++ (cli) but with native exporting. I have added to linker -> input -> assembly link resource the dll of the library from which the function is exported. But native c++ linking requires .lib file to "see" implementations in cpp correctly, so for me helped to add the .lib file to linker -> input -> additional dependencies.
[Usually managed code does not use dll export and import, it uses references, but that was unique situation.]