C++静态成员变量为什么要类外初始化

本文详细介绍了C++中静态成员变量的概念、特性,如共享内存、生命周期、类内外初始化的规定,以及为何C++不支持静态成员变量的默认初始化,以避免链接时的多重定义问题。
摘要由CSDN通过智能技术生成

静态成员变量是一种特殊的成员变量,类体中的数据成员声明时前面加上关键字static,即成为该类的静态数据成员。首先罗列一下C++静态成员变量的一些知识点。

  • 所有对象共享共享静态成员变量的同一份内存:
    静态成员变量属于类,不属于某个具体的对象。即使创建多个对象,也只为其分配一份内存,所有对象使用的是这份内存中的数据,当某个对象修改了静态成员变量的值,也会影响到其他的对象。static成员变量不占用对象内存,在所有对象外开辟内存,不创建对象也可以访问
  • 编译阶段就分配内存:
    对于静态成员变量而言,它们的生命周期与类的生命周期相关联,而不是与类的实例的生命周期相关联。编译时在静态数据区分配内存,到程序结束时才释放。这就意味着static成员变量不随对象的创建而分配内存,也不随对象的销毁而释放内存。而普通成员变量在对象创建时分配内存,在对象销毁时释放内存。
  • 静态成员变量实际上就是类域中的全局变量,类内声明,类外进行初始化操作
  • 初始化时不受private和protected访问限制。

上述知识点体现在如下代码中:

class Person
{
public:
	static int m_A;

private:
	static int m_B;

protected:
	static int m_C;
};
int Person::m_A = 99;
//初始化不受private访问限制
int Person::m_B = 100;
int Person::m_C = 100;

int main() 
{
	// 通过对象进行访问静态成员变量
	Person p1;
	cout <<"p1.m_A: " << p1.m_A << endl;

	//所有对象共享共享静态成员变量的同一份内存
	p1.m_A = 66;
	Person p2;
	cout << "p2.m_A: " << p2.m_A << endl;

	// 通过类名进行访问静态成员变量
	cout <<"Person::m_A: " << Person::m_A << endl;

	return 0;
}

输出结果如下:

那为什么C++的静态成员变量要设计成必须类内声明,类外显式初始化呢?为什么不能像其他成员变量一样会默认初始化呢?

C++中的静态成员变量是属于整个类的,而不是属于类的任何特定实例。如果C++为静态成员变量提供默认初始化值,那么可能会导致以下问题:

  1. 多次定义:
    如果静态成员变量有默认初始化值,且在多个源文件中都包含了该类的定义,那么编译器会在每个源文件中生成对静态成员变量的初始化代码,从而导致链接时的多重定义错误。
    假设有一个类MyClass,其中包含一个静态成员变量staticVar ,如果C++允许静态成员变量默认初始化,那么可能会出现以下情况:
    MyClass.h:
    // MyClass.h
    #pragma once
    
    class MyClass {
    public:
        static int staticVar; // 静态成员变量声明
    };
    

    File1.cpp:

    // File1.cpp
    #include "MyClass.h"
    
    // 如果静态成员变量有默认初始化值
    // 那么这里可能会生成初始化代码
    // static int MyClass::staticVar = defaultValue;
    

    File2.cpp:

    // File2.cpp
    #include "MyClass.h"
    
    // 同样,这里也可能生成初始化代码
    // static int MyClass::staticVar = defaultValue;
    

    如果staticVar有默认初始化值,并且同时在File1.cpp和File2.cpp中包含了对MyClass的定义,那么在链接时就会出现多次定义的错误。因为每个源文件中都尝试对staticVar进行初始化。
    类似于普通变量的重定义

    //重复定义会报错
    int a = 10;
    int a = 11;
    

    为了避免这种问题,C++不允许对静态成员变量进行默认初始化,而需要在类外部单独进行一次定义和初始化。

    class Person
    {
    public:
    	static int m_A;
    
    private:
    	static int m_B;
    
    protected:
    	static int m_C;
    };
    int Person::m_A = 99;
    //初始化不受private访问限制
    int Person::m_B = 100;
    int Person::m_C = 100;

    注意使用作用域解析运算符::来访问静态成员变量,而不是使用实例化对象后再用.来访问。在C++中,静态成员变量属于类,而不是类的实例。我们使用Person::m_A来表示它属于MyClass类,而不是MyClass类的实例。
    这样可以明确地表示这是一个静态成员变量,并且不依赖于任何特定的类实例。

  2. 不确定性:
    静态成员变量的默认初始化值可能会因编译器、平台或环境的不同而产生差异,这会导致程序行为的不确定性。

---------------------------------------------------------------------------------------------------------------------------------如果有讲的不对的,请大家指正!

  • 36
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值