上篇C++57个入门知识点_41_初始化列表实现常成员变量和成员对象的初始化(初始化列表可以用于初始化普通成员变量/常成员变量(注意新旧编译器的写法,建议用旧的);也可以用来初始化有参数的成员对象)介绍了重要的关键字const
,本篇介绍另一个重要的关键字static
及在类中出现static
表示什么意思?
静态成员变量总结:
static int m_nStatic;(代表静态成员是在类域内)
,实现要单独的写在类外(cpp
中,不写在.h
中)- 默认会用
0
对该成员进行初始化 - 静态成员变量是不同的对象(同一个类)公用的,不占用某个对象的大小
CInteger::m_nStatic = 1;
实现不用产生对象就可以访问静态成员变量- 本质:带类域的全局变量,虽然是全局变量但是有类域的限制,解决名称限制
- 静态成员声明和初始化方法:
.h
中声明:static int m_nStatic;
.cpp
中初始化:int CInteger::m_nStatic = 123;
在C中我们学过static
关键字,参考C语言基础入门48篇_44_静态局部变量、静态全局变量、静态函数(静态局部变量只被初始化一次,保留变量值、静态全局变量是加了作用域的全局变量、静态函数亦是加了作用域的函数),本篇将static修饰成员变量的情况。
1. 静态成员变量的声明及实现
我们在原先的基础上直接增加静态成员变量,会报比较有意思的错误,代码如下:
#include <iostream>
class CInteger
{
public:
CInteger(int nNumber) {
m_nNumber = nNumber;
}
int GetNumber()const;
void SetNumber(int nNumber) {
m_nNumber = nNumber;
}
//静态成员变量
static int m_nStatic;
private:
int m_nNumber;
};
//int CInteger::GetNumber()const
//{
// return m_nNumber;
//}
int main()
{
CInteger i = 1;
i.m_nStatic = 123;
i.GetNumber();
return 0;
}
运行结果:报错如下
程序中的错误可能是编译错误
或者链接错误
:
- 编译错误:由于代码错误导致的编译不通过;
- 链接错误:代码在多个
Obj
再组合成exe
过程中发现少了某些东西,上面的代码很明显就是报的Link
的链接错误。
报错和我们注释掉的函数是一样的,相当于只写了声明,没有写实现,解决思路也是一样的,给静态成员变量写上实现,并且注意:静态成员变量static int m_nStatic;(代表静态成员是在类域内)
实现要单独的写在类外(cpp中,不写在.h中)
不放在.h
文件中的原因: 是因为在编译器在编译时会将.h
中的所有内容统统拷贝到#include
下,如果放在.h
文件中,静态成员变量会被重复定义
#include <iostream>
class CInteger
{
public:
CInteger(int nNumber) {
m_nNumber = nNumber;
}
int GetNumber()const;
void SetNumber(int nNumber) {
m_nNumber = nNumber;
}
//静态成员变量
(1)实现要单独的写在类外(cpp中,不写在.h中)
static int m_nStatic;
private:
int m_nNumber;
};
int CInteger::GetNumber()const
{
return m_nNumber;
}
//实现静态成员变量
int CInteger::m_nStatic;
int main()
{
CInteger i = 1;
i.m_nStatic = 123;
i.GetNumber();
return 0;
}
这样就可以编译通过了。
2. 静态成员变量的初始化
- 初始化一般放在实现的地方
- 若没有初始化,默认会用0对该成员进行初始化
CIntreger.cpp:
int CInteger::m_nStatic = 123;
3. 静态成员变量的性质
3.1 不同对象的成员的静态成员是共用的
静态成员变量是不同的对象(同一个类)公用的,不占用某个对象的大小。
从下图中可以看到,对象中并没有包含静态成员变量,这是为什么呢?
利用sizeof()
查看类的大小:
前面我们知道:成员函数是对象所共有的,成员变量是对象私有的,按道理CInteger
类中应该有两个int
型数据,分别为static int m_nStatic
和int m_nNumber
,应该占8
字节。
class CInteger
{
public:
CInteger(int nNumber) {
m_nNumber = nNumber;
}
int GetNumber()const;
void SetNumber(int nNumber) {
m_nNumber = nNumber;
}
//静态成员变量
//(1)要单独的实现写在类外(cpp中,不写在.h中)
static int m_nStatic;
private:
int m_nNumber;
};
很明显,静态成员变量nSize
并不包含在内,下面可以通过创建两个对象,查看对象静态成员变量的地址来验证。
3.2 没有对象的情况下访问静态成员
既然静态成员是属于类的,属于所有对象共用,那可不可以不产生对象就访问静态成员呢?答案是可以的CInteger::m_nStatic = 1;
就可以实现不用产生对象就访问静态成员。
int main()
{
//不用创建对象就可以创建静态变量,因为它是与类相关的,一个类有一个
//属于类而不单属于某个对象,是类公有的
//CInteger::表示在类域范围内
CInteger::m_nStatic = 1;
return 0;
}
4. 静态成员变量的本质
#include <iostream>
#include "CIntreger.h"
int nGlobal = 3;
int main()
{
CInteger::m_nStatic = 1;
nGlobal = 3;
return 0;
}
CInteger::m_nStatic
类似于nGlobal
全局变量,但是具有类域的限制。
本质:带类域的全局变量,虽然是全局变量但是有类域的限制,解决名称限制
5. VS中增加一个类的方法
VS中创建一个类,并将类的代码放入后,整体结构如下图:
此处加上如何在VS创建一个同名的.h及.cpp文件方法,只需两步:
6. 代码及注释
CIntreger.h:
class CInteger
{
public:
CInteger(int nNumber) {
m_nNumber = nNumber;
}
int GetNumber()const;
void SetNumber(int nNumber) {
m_nNumber = nNumber;
}
//静态成员变量
//(1)要单独的实现写在类外(cpp中,不写在.h中)
//(2)默认会用0对该成员进行初始化
//(3)静态成员变量是不同的对象(同一个类)公用的,不占用某个对象的大小
//(4)本质:带类域的全局变量,虽然是全局变量但是有类域的限制,解决名称限制
static int m_nStatic;
private:
int m_nNumber;
};
CIntreger.cpp:
#include "CIntreger.h"
int CInteger::GetNumber()const
{
return m_nNumber;
}
//静态成员变量的实现,若没有的话报错类似写了声明没写实现
//一般不写在.h文件中,否则会被重复调用两次报错
//若没有初始化,默认会用0对该成员进行初始化
int CInteger::m_nStatic=123;
TestC11.cpp:
#include <iostream>
#include "CIntreger.h"
int main()
{
//不用创建对象就可以创建静态变量,因为它是与类相关的,一个类有一个
//属于类而不单属于某个对象,是类公有的
//CInteger::表示在类域范围内
CInteger::m_nStatic = 1;
//CInteger i1 = 1;
//CInteger i2 = 1;
//类的size只有4字节,为非静态变量的m_nNumber
int nSize = sizeof(CInteger);
/*i.m_nStatic = 123;*/
//分别获取两个静态变量的地址
//int* pStatic1 = &i1.m_nStatic;
//int* pStatic2 = &i2.m_nStatic;
return 0;
}
7. 学习视频地址: C++57个入门知识点_42:静态成员变量理解