在C++中,写在类里面的可以理解是声明,而不是定义。所以,当我们在类内定义一个静态成员的时候,需要在类外定义静态成员的存在。
#include
using namespace std;
class A{
public:
A(){ i = 0; }
void print(){ cout << i << endl; }
void set(int t){ i = t; }
private:
static int i;
};
int A::i; //定义A类中存在的静态成员
int main()
{
A a,b;
a.set(6);
b.print();
return 0;
}
如果没有int A::i
这个说明,那么编译可以通过,链接失败。
提示:无法解析的外部符号”symbol”,即代码引用链接器无法在库和对象文件中找到的内容 (如函数、 变量或标签)。
静态成员只能在定义的时候去初始化,所以不能在初始化列表中去初始化静态成员。
#include
using namespace std;
class A{
public:
A():i(3){ }
//error int A::i is a static data member,it can only be initialized at its definition
void print(){ cout << i << endl; }
void set(int t){ i = t; }
private:
static int i;
};
int A::i;
int main()
{
A a,b;
a.set(6);
b.print();
return 0;
}
error C2438: “i”: 无法通过构造函数初始化静态类数据,即初始化列表无法初始化静态类数据(初始化列表只能对非静态的成员做初始化)。
为什么static成员一定要在类外初始化? 因为静态成员属于整个类,而不属于某个对象,如果在类内初始化,会导致每个对象都包含该静态成员,这是矛盾的。
什么东西能在类内初始化?
能在类中初始化的成员只有一种,那就是静态常量成员(自从c++11开始,允许在定义时直接初始化成员变量,在c++11之前只有static const整型变量才能在类定义中初始化。)。
也就是说,被static声明的类静态数据成员,其实体远在main()函数开始之前就已经在全局数据段中诞生了(见《Inside The C++ Object Model》page247)!其生命期和类对象是异步的,(而且静态语意说明即使没有类实体的存在,其静态数据成员的实体也是存的)这个时候对象的生命期还没有开始,如果你要到类中去初始化类静态数据成员,让静态数据成员的初始化依赖于类的实体,,那怎么满足前述静态语意呢?难道类永远不被实例化,我们就永远不能访问到被初始化的静态数据成员吗?
静态数据成员有this指针,静态成员函数没有this指针。
#include
using namespace std;
class A
{
public:
A() { }
void print() { std::cout << i << std::endl; }
void set(int i) { this->i = i; }//静态数据成员有this指针,静态成员函数没有this指针
private:
static int i;
};
int A::i = 20;
void main()
{
A a, b;
a.set(6);
b.print();
return 0;
}
static静态数据成员实际上是全局变量,如果静态成员是public的,那么可以通过对象访问i,也可以通过类访问i。
#include
using namespace std;
class A
{
public:
A() { }
void print() { std::cout << i << std::endl; }
void set(int i) { this->i = i; }
static int i;
};
int A::i = 20;
void main()
{
A a, b;
a.set(6);
b.print();
std::cout << a.i << std::endl;//通过对象访问i
std::cout << A::i << std::endl;//通过类访问i
return 0;
}
但是,如果静态成员是private的,那么无法访问 private 成员(在“A”类中声明)。
#include
using namespace std;
class A
{
public:
A() { }
void print() { std::cout << i << std::endl; }
void set(int i) { this->i = i; }
private:
static int i;
};
int A::i = 20;
void main()
{
A a, b;
a.set(6);
b.print();
std::cout << a.i << std::endl;//error C2248: “A::i”: 无法访问 private 成员(在“A”类中声明)
std::cout << A::i << std::endl;//error C2248: “A::i”: 无法访问 private 成员(在“A”类中声明)
return 0;
}
在静态函数成员里面使用非静态成员变量是非法的。静态函数只能访问静态成员变量。
#include
using namespace std;
class A
{
public:
A() { }
void print() { std::cout << i << std::endl; }
void set(int i) { this->i = i; }
static void say(int ii) { std::cout << ii << " " << k << endl; }
//error C2597: 对非静态成员“A::k”的非法引用,非静态成员k的引用必须与特定对象相对
private:
int k;
static int i;
};
int A::i = 20;
void main()
{
A a, b;
a.set(6);
b.print();
a.say(0);
A::say(0);
return 0;
}
在C++中,“this”: 只能在非静态成员函数或非静态数据成员初始值设定项的内部引用。
#include
using namespace std;
class A
{
public:
A() { }
void print() { std::cout << i << std::endl; }
void set(int i) { this->i = i; }
static void say(int ii) { std::cout << ii << " " << this->i << endl; }//this只能用于非静态成员函数内部
// error C2355 : “this” : 只能在非静态成员函数或非静态数据成员初始值设定项的内部引用
// error C2227 : “->i”的左边必须指向类 / 结构 / 联合 / 泛型类型
private:
int k;
static int i;
};
int A::i = 20;
void main()
{
A a, b;
a.set(10);
b.print();
a.say(0);
A::say(0);
return 0;
}