There are two aspects to your question: code and data.
I'll start with data. Consider this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
#include <iostream>
extern unsigned int y;
class A{
public:
static unsigned int x;
};
unsigned int A::x = 500;
unsigned int y = 400;
int main(){
std::cout
<< "x: " << A::x << std::endl
<< "y: " << y << std::endl;
return 0;
}
| |
What's the difference between A::x and y? Nothing, really, right? They both exist independently of any other objects. The only difference is that to access A::x the compiler requires you to specify that you're in the lexical scope of A. Static class members are basically equivalent to global objects. The only difference is syntactical. While the program is running you would not be able to distinguish if a variable being accessed is a static class member or a global.
Now for code. Unlike data, functions always "exist". Whether the class has been instantiated or not, you can always access a function. Consider this:
1 2 3 4 5 6 7 8 9 10 11 12
|
#include <iostream>
class A{
public:
void f(){
std::cout << "hello";
}
};
int main(){
((A *)nullptr)->f();
}
| |
Technically the behavior of this code is undefined, but on basically every implementation, the output of that program will be "hello". Yet, you're calling a member function even though no instances of A were ever created. It works because code is not created on the fly as the program is running. The compiler generates all code ahead of time. The above code is basically equivalent to this:
1 2 3 4 5 6 7 8 9 10 11
|
class A{
public:
};
void A_f(A *this_pointer){
std::cout << "hello";
}
int main(){
A_f(nullptr);
}
| |
Non-static member functions are simply functions that exist in a particular lexical scope and which take an (often) implicit parameter: the
this
pointer. They're basically a little bit of syntactic sugar.
So what about static member functions? They're the same a non-static member functions, except they don't take that implicit parameter.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
|
#include <iostream>
class A{
public:
int x;
static int y;
void f(){
std::cout
<< "x: " << x << std::endl
<< "this->x: " << this->x << std::endl;
}
static void g(){
std::cout << "y: " << y << std::endl;
}
};
int A::y = 42;
int main(){
A::g();
A a;
a.x = 31;
a.f();
}
| |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
|
#include <iostream>
class A{
public:
int x;
};
int A_y = 42;
void A_f(A *This){
std::cout
<< "x: " << This->x << std::endl
<< "this->x: " << This->x << std::endl;
}
void A_g(){
std::cout << "y: " << A_y << std::endl;
}
int main(){
A_g();
A a;
a.x = 31;
A_f(&a);
}
| |