C++ 静态成员

在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;
}

你可能感兴趣的:(c++)