So I have a file called test.cpp
class Entity
{
int c = 0;
int b = 0;
int d = 5;
};
And then another called main.cpp
#include<iostream>
#include<vector>
#include<algorithm>
class Entity
{
int a = 5;
int b = 0;
};
int main()
{
}
Why does this link and work just fine? Doesn't the linker see that there are 2 classes with the same name and different data members? Also would these be considered class definitions? If I wanna declare this class in a header file I would just do what I did here right? Even though I'm technically defining variables it's still just a class declaration right..?
It is an ill-formed program.
As the class definition has external linkage then each definition of the class shall consist of the same sequence of tokens.
On the other hand, as neither code from the translation unit test.cpp is used the linker can exclude it from the final exe file.
Related
Just trying to grab the concept revolving around the scope of the Class in C++. If we take an example something like:
#include <iostream>
using namespace std;
string barValue="OUTSIDE CLASS";
class foo
{
public:
void print_bar()
{
cout<<barValue<<endl;
}
};
int main()
{
foo f;
f.print_bar();
return 0;
}
I am wondering:
Is the barValue variable is in the Class scope?
Can the barValue be accepted even if it is defined in one of the included files?
Is the file and all the included files can be called as the scope of the foo Class?
I can understand that the barValue will not be considered if it is defined after the Class body. To follow up is that means all the included files comes before the Class body and in general before the current file content?
Question 1
Is the barValue variable is in the class scope?
barValue is a global variable since you have defined it outside any function and class. Therefore barValue can be used inside the class as you did.
Question 2
Can the barValue be accepted even if it is defined in one of the included files?
Yes even if barValue is defined in a header file it can be used in other files because/if it has external linkage as shown in the below example.
file.h
int barvalue = 34;//barvalue has external linkage
main.cpp
#include <iostream>
#include "file.h"
int main()
{
std::cout<<barvalue<<std::endl;//prints 34
return 0;
}
Question 3
Is the file and all the included files can be called as the scope of the foo class?
No
Question 4
I can understand that the barValue will not be considered if it is defined after the class body. To follow up is that means all the included files comes before the Class body and in general before the current file content?
You should clarify this question more because i think it is not clear what your are asking here but i will try to answer what i understand from your question.
If you define barValue after the class foo definition then the program will not work because since you have defined it after the class definition, therefore it has not been defined/declared at the point when you write cout<<barValue<<endl; which is what the error says as shown below:
#include <iostream>
using namespace std;
class foo
{
public:
void print_bar()
{
cout<<barValue<<endl;//error: ‘barValue’ was not declared in this scope
}
};
int main()
{
foo f;
f.print_bar();
return 0;
}
string barValue="OUTSIDE CLASS";
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.]
If I have a class similar to this :
//body.h
class Body
{
static int i;//line 1
};
int Body::i=2;/line 2
and a class like this:
//ball.h
#include <body.h>
//line 3
class Ball:public Body
{
int f();
};
and in ball.cpp :
int Ball::f()
{
return 1;
}
this results in multiple definition of i.
I tried putting extern in line1,line2 and defining it in line 3 and still having the same error, I also searched the web, most of the results I find talks about a variable declared solely(not in a class) while I have a static class variable.
I understood that extern is opposite to static but making i extern in line1 didn't help, also I saw many questions in SO , this talks about namespaces which I don't want, this doesn't address my issue.
As A note, there is no body.cpp, there are classes other than Ball that inherits body and there is main.cpp which will access all the children classes.
So what to do to be able to use Body::i outside body.h ?
PS
all classes are surrounded in header guards .
Create another translation unit Body.cpp and move the definition there
int Body::i=2;
Even with header guards, as you mention to have them, the definition appears in multiple translation units, hence the multiple definition error.
In your particular case the static class member is a primitive, and can be initialized at the point of declaration alternatively:
class Body {
static int i = 2;
};
You should not define the static member in the header. You need to make a source (.cpp) file for it:
body.h (declare statics but don't define)
class Body
{
static int i; // only declare
};
// int Body::i=2; // do not define it here
body.cpp (define statics here)
#include "body.h"
int Body::i = 2; // now we define it
Could someone please advise?
If const in C++ defaults to internal linkage, why do I get multiple definition errors in the code below?
First, the file dem.h:
#ifndef _DEM_H_
#define _DEM_H_
class Dem {
public:
static const int i;
};
const int Dem::i = 10;
#endif
Them imp1.cpp:
#include "dem.h"
#include <iostream>
using namespace std;
extern int foo();
int main() {
cout << foo() << endl;
}
and imp2.cpp:
#include "dem.h"
int foo() {
return Dem::i ;
}
I compile with the following command and results:
$ g++ imp1.cpp imp2.cpp
/tmp/ccmGt0OY.o:imp2.cpp:(.rdata+0x0): multiple definition of `Dem::i'
/tmp/cc5sN7dz.o:imp1.cpp:(.rdata+0x0): first defined here
collect2: ld returned 1 exit status
From C++11 [basic.link], paragraph 5:
In addition, a member function, static data member, a named class or enumeration of class scope, or an unnamed class or enumeration defined in a class-scope typedef declaration such that the class or enumeration has the typedef name for linkage purposes (7.1.3), has external linkage if the name of the class has external linkage.
Because your class has external linkage, so does your static data member.
Its static to the compilation unit. You are compiling in two steps - first impl1.cpp and then impl2.cpp - and in each unit the compiler instantiates the static data member. When the linker then tries to link the two associated object files together, it sees two different definitions for the same symbol , and so you get a multiple definition error.
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.]