得之我幸 失之我命

when someone abandons you,it is him that gets loss because he lost someone who truly loves him but you just lost one who doesn’t love you.

类内的 static

静态成员变量

静态成员变量是一种特殊的成员变量,它以关键字 static 开头,这种成员变量的生存期大于 class 的对象(instance)。静态成员变量是每个 class 有一份,普通数据成员是每个对象各自拥有一份,因此静态成员变量也叫做类变量

1
2
3
4
5
6
class Test
{
public:
static int n;
};
int Test::n; // 不赋值,会被默认初始化

静态成员变量属于类不属于对象,不创建对象也可以通过类名作用域调用访问,也可以通过对象调用(非静态成员变量只能通过对象调用)

1
2
3
4
5
6
7
8
9
10
11
12
13
class Test
{
public:
static char c;
int i;
};
char Test::c = 'a';
int main()
{
cout << Test::c << endl; // a,通过类名作用域调用访问
Test t;
cout << t.c << endl; // a,通过对象调用
}

静态成员变量的内存空间既不是在声明类时分配,也不在创建对象时分配,只有在初始化时才分配空间;初始化时可以赋初值,也可以不赋值;如果不赋值,那么会被默认初始化;静态成员变量编译时在静态数据区分配内存,到程序结束时释放;初始化在类外进行,前面不加 static,以免与一般静态变量或对象相混淆

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
class Test
{
public:
static char c;
int i;
};
int main()
{
cout << sizeof(Test) << endl; // 4,静态成员变量的内存空间不在声明类时分配
Test t;
cout << sizeof(t) << endl; // 4,静态成员变量的内存空间不在创建对象时分配
}

// 无初始化,链接报未定义的错
class Test
{
public:
static char c;
};
int main()
{
cout << Test::c << endl; // (.text+0xa): undefined reference to `Test::n'
}

class Test
{
public:
static char c;
};
char Test::c; // 类外默认初始化
int main()
{
cout << int(Test::c) << endl; // 0
}

class Test
{
public:
static char c;
};
char Test::c = 'A'; // 类外显式初始化
int main()
{
cout << int(Test::c) << endl; // 65
}

// 静态成员变量类内初始化,编译报错,因为静态成员属于整个类,而不属于某个对象,如果在类内初始化,会导致每个对象都包含该静态成员,这是矛盾的
class Test
{
public:
static char c = 'A'; // error: ISO C++ forbids in-class initialization of non-const static member ‘Test::c’
};

❓只有静态常量整型数据成员可在类内初始化,也可在类外初始化(C++11 之前的标准),猜测原因可能跟后面出现的 constexpr 有关联

1
2
3
4
5
6
7
8
9
class Test
{
public:
static const char c = 'A';
};
int main()
{
cout << Test::c << endl; // A
}

但是,即使是静态常量整型数据成员,也存在不被允许的情况

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
26
27
28
29
30
31
32
33
class Test
{
public:
static const char c = 'A';
};
int main()
{
cout << &Test::c << endl; // 链接报未定义,(.text+0xb): undefined reference to `Test::c'
}

// 直接在类外追加一个初始化呢?
class Test
{
public:
static const char c = 'A';
};
const char Test::c = 'A'; // error: duplicate initialization of ‘Test::c’
int main()
{
cout << &Test::c << endl;
}

// 正确的写法
class Test
{
public:
static const char c;
};
const char Test::c = 'A';
int main()
{
cout << &Test::c << endl; // A
}

静态成员函数

成员函数也可以定义为静态的,在类中声明函数的前面加 static 就成了静态成员函数,和静态成员变量一样,静态成员函数是类的一部分,而不是对象的一部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Test
{
public:
static void show()
{
cout << n << endl;
}
private:
static int n;
};
int Test::n = 1;
int main()
{
Test::show(); // 1,通过类名作用域调用
Test t;
t.show(); // 1,通过对象调用
}

与静态成员变量不同的是,静态成员函数的作用是为了能处理静态成员变量。当调用一个对象的成员函数(非静态成员函数)时,系统会把该对象的起始地址赋给成员函数的 this 指针;而静态成员函数并不属于某一对象,因此静态成员函数没有 this 指针,既然它没有指向某一对象,就无法对一个对象中的非静态成员进行默认访问(即在引用数据成员时不指定对象名)

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
// 静态成员函数访问非静态成员变量和非静态成员函数,编译报错
class Test
{
public:
static void show()
{
add(7); // error: cannot call member function ‘void Test::add(int)’ without object
cout << i << endl; // error: invalid use of member ‘Test::i’ in static member function
}
void add(int j)
{
i += j;
}
private:
int i;
};

// 但是,静态成员函数并不是绝对不能引用本类中的非静态成员,只是不能进行默认访问,因为无法知道应该去找哪个对象
class Test
{
public:
static void show(Test a)
{
a.add(7);
cout << a.i << endl;
}
void add(int j)
{
i += j;
}
private:
int i;
};

// 非静态成员函数可以访问静态成员函数和静态成员变量
class Test
{
public:
void show()
{
add(i);
cout << n << ' ' << i << endl;
}
static void add(int j)
{
n += j;
}
private:
int i{7};
static int n;
};
int Test::n = 1;
int main()
{
Test t;
t.show(); // 8 7
}

be slow to promise and quick to perform.