首页 > 编程语言 >[C++] static静态成员变量/函数的用法

[C++] static静态成员变量/函数的用法

时间:2023-12-22 21:05:53浏览次数:45  
标签:变量 静态 成员 C++ 用法 对象 int static 函数

  • 作者: 丶布布


文章预览:

  • 一. 回顾成员变量
  • 二. 静态成员概念的引入
  • 三. 静态成员变量
  • 四. 静态成员函数



一. 回顾成员变量

普通成员变量的特点:

  1. 通过对象名能够访问中的public成员变量。
  2. 每个对象的成员变量都是专属的,即使是同个的不同对象之间也不能共享该的成员变量。

这么来看,如果多个对象想操作同一个数据,从目前来看只能使用全局变量(每个对象都可以操作全局作用域的全局变量),但是这样存在安全隐患,在现代软件开发中不推荐这种方式。那么,有没有其它更好的方式呢?


二. 静态成员概念的引入

  1. 统计在程序运行期间某个类的对象数目。
  2. 保证程序的安全性 ==> 不能使用全局变量( 由于全局变量在程序的任何地方都可能被修改,因此不推荐使用全局变量)。
  3. 随时可以获取当前对象的数目。

针对上面新的需求,我们就引入了类的静态成员变量的概念。


三. 静态成员变量

1. 定义静态成员变量以关键字static开头,是一种特殊的类成员变量

2. 语法

C++中,静态成员变量静态成员函数的使用方法如下:

#include <iostream>
#include <string> 
using namespace std;

//静态成员变量在类内定义,类外初始化
class test
{
private:
    static int m_value;		//定义类的静态成员变量
 
public:
    static int getValue(){	//定义类的静态成员函数
    	return m_value;
    }
};
 
int test::m_value = 12;		//类的静态成员变量需要在类外分配内存空间,可以不给初值,那么系统默认给0

定义完静态成员变量之后,通过类对象来调用静态成员变量/函数:

int main()
{
    test t;
 
    cout << t.getValue() << endl;
    system("pause");
}

注意静态成员变量在类内定义的时候由于还没有被分配内存空间,所以不能被直接赋初值。需要在类外(头文件的结尾或者源文件的开头)赋初值分配内存空间,这样就能够保证在调用任何函数之前静态成员已经被成功初始化。


3. 静态成员变量的特点

1)静态成员变量隶属于整个类所有所有类的对象共享其静态成员变量

这就意味着,即使创建多个对象,也只为静态分配一份内存,所有对象使用的都是这份内存中的数据,我们一旦在某个对象中修改了这个成员变量的值,在其他对象中能够直接看到修改的结果。

2)静态成员变量的生命周期不依赖于任何对象:原因是其在全局(静态)存储区内分配空间,所以它生命周期是从程序开始到程序结束。

  • 全局变量静态局部变量静态全局变量保存在全局(静态)存储区,生命周期是从程序开始到程序结束。
  • 局部变量保存在,其数据则随着函数等的作用域结束导致出栈而销毁。

可见,静态局部变量的效果已经跟全局变量有一拼了,而且因为位于函数体内部,所以更有利于程序的模块化了。

Tips:全局变量作用区间是在各个类中实现数据共用的方法——extern

//类A.cpp:
int g_abc = 15;

//类B.cpp:
extern int g_abc;
cout << g_abc << endl;  //输出15

3)可以通过类名直接访问公有静态成员变量。    
语法:类名 :: 静态成员变量名(Class_name :: static_member

4)可以通过对象名访问公有静态成员变量。

5)静态成员变量在类内定义,类外初始化:
因为静态成员属于整个类,而不属于某个对象,如果在类内初始化,会导致每个对象都包含该静态成员,这是矛盾的。


4. 静态变量的使用

针对静态成员变量的以上的几个特点,我们把上边的代码修改如下,用于统计当前对象的个数:

#include <iostream>
#include <string>
using namespace std;
 
class test
{
private:
    static int m_value1;		//定义私有类的静态成员变量
public:
    static int m_value2;		//定义公用类的静态成员变量(公有的问题在结论)
 
public:
    test(){
    	m_value1++;
    	m_value2++;
    }
 
    int getValue(){	        //定义类的成员函数(和静态成员函数的用法区别)
    	return m_value1;
    }
};
 
int test::m_value1 = 0;		//类的静态成员变量需要在类外分配内存空间
int test::m_value2 = 0;		//类的静态成员变量需要在类外分配内存空间
int main()
{
    test t1, t2, t3;

    cout << "test::m_value2 = " << test::m_value2 << endl;	//通过类名直接调用公有静态成员变量,获取对象个数
    cout << "t3.m_value2 = " << t3.m_value2 << endl;		//通过对象名名直接调用公有静态成员变量,获取对象个数
    cout << "t3.getValue() = " << t3.getValue() << endl;	//通过对象名调用普通函数获取对象个数
}

编译输出:

test::m_value2 = 3
t3.m_value2 = 3
t3.getValue() = 3

从输出,貌似得到我们想要的效果,但是C++中讲究的是封装性,以上代码,有2个不妥之处:

  1. 类名或对象名能直接访问成员变量(因为是public类型),也就是说成员变量能直接被外界修改。
    修改: 应将静态变量定义为private类型。
  2. 这里我们使用了一个成员函数来获取当前的对象个数,看似没问题,但是必须要定义对象test t3,通过对象去调用成员函数,即t3.getValue()。但有时候我们不想定义对象,也能直接使用类中的成员函数,这就是我们要说的类的静态成员函数
    等价写法:将成员函数getValue()定义为静态类型的,就可以通过test::getValue()直接使用。

5. 小结

静态成员变量的优势如下:

1)安全地实现共享数据

全局变量的值也可以为一个程序中的多个函数所共享,但是全局变量的安全性得不到保证,由于在各处都可以自由地修改全局变量的值,很有可能偶然失误,全局变量的值就被修改,导致程序的失败。因此在实际开发中很少使用全局变量

因为同类不同对象之间的所占的内存空间是不一样的,这也导致各个对象之间成员变量的数据没法互用。而静态成员变量恰恰解决了这个问题,它可以在同类的多个对象之间实现数据共享,也可以实现信息隐藏,静态数据成员可以是private成员,而全局变量不能(当程序想要使用全局变量的时候应该先考虑使用 static)。

2)节省内存,效率高

因为静态变量所有对象所公有的,因此,对多个对象来说,静态数据成员只存储一处,供所有对象共用。只要对静态数据成员的值更新一次,保证所有对象存取更新后的相同的值,这样可以提高时间效率。


四. 静态成员函数

1. 定义:和静态成员变量一样,静态成员函数以关键字static开头,在C++中,定义静态成员函数主要目的处理类的静态成员变量

2. 静态成员函数的特点

  1. 普通成员函数静态成员函数之间有一个主要的区别。那就是静态成员函数没有this指针(静态成员函数属于整个所有)
  2. 静态成员函数只能直接访问静态成员变量和静态成员函数不可以调用或操纵非静态成员
  3. 可以通过类名直接访问类的公有静态成员函数
  4. 可以通过对象名访问类的公有静态成员函数
  5. 为了调用方便,静态成员函数的调用不需要通过类的实例化,通过作用域::就可以被调用。

特点2的错误示范

class test
{
  int number;
  static void picker()
  {
    number = 6;  //不被允许,静态成员函数只能访问静态成员变量/静态成员函数
  }
}

3. 静态成员函数的用法

针对上述特点,对上面的代码进行成员函数修改成静态成员函数并调用:

#include <iostream>
#include <string>
 using namespace std;
 
class test
{
private:
    static int m_value;		//定义私有类的静态成员变量
 
public:
    test(){
    	m_value++;
    }
 
    static int getValue(){		//定义类的静态成员函数    
    	return m_value;
    }
};
 
int test::m_value = 0;		//类的静态成员变量需要在类外分配内存空间
int main()
{
    test t1,t2,t3;
 
    cout << "test::getValue() = " << test::getValue() << endl;	//通过类名直接调用公有静态成员函数,获取对象个数
    cout << "t3.getValue() = " << t3.getValue() << endl;		//通过对象名调用静态成员函数获取对象个数
    system("pause");
}

编译输出:

test::m_value2 = 3
t3.getValue() = 3

这样我们就直接能通过类名::静态成员函数的方式去访问静态成员函数,获取对象个数,而不需要任何类的实例化对象来实现调用。

静态成员函数的其他用法:

  1. 可以实现某些特殊的设计模式:如单例模式—Singleton
  2. 可以封装某些算法,比如数学函数,如lnsintan等等,这些函数本就没必要属于任何一个对象,所以从类上调用感觉更好,比如定义一个数学函数类Math,调用Math::sin(3.14);如果非要用非静态函数,那就必须:Math math; math.sin(3.14); 行是行,只是不爽。

4. 静态成员函数与普通成员函数的对比

静态成员函数

普通成员函数

所有对象共享

Yes

Yes

隐含this指针

No

Yes

访问普通成员变量(函数)

No

Yes

访问普通静态变量(函数)

Yes

Yes

通过类名直接调用

Yes

No

通过对象名直接调用

Yes

Yes

最重要的是要记住:静态函数不需要实例化就可以被调用,不会也不可以调用或操纵非静态成员。


下雨天,最惬意的事莫过于躺在床上静静听雨,雨中入眠,连梦里也长出青苔。


标签:变量,静态,成员,C++,用法,对象,int,static,函数
From: https://blog.51cto.com/u_16436086/8938518

相关文章

  • [C++从入门到精通] 2.inline内联函数、const的相关用法
    作者:丶布布文章预览:一、返回类型二、内联函数inline三、函数杂合用法总结四、constchar*、charconst*、char*const三者的区别五、函数形参中带const一、返回类型前置类型:在函数声明和定义的时候,把函数返回类型写到函数名字之前的形式,叫前置返回类型voidfunc(inta);//函数......
  • [C++从入门到精通] 3.string类型的相关用法
    作者:丶布布文章预览:一.C++基本变量类型二.String对象的定义和初始化三.String对象的操作一.C++基本变量类型基本类型:int、double等。复合类型:引用、指针、const等。标准库类型:string(可变长字符串的处理)、vector(一种集合或容器的概念)、迭代器。对于字符串,在现实生活中,string......
  • [C++] 获取工程路径、解决方案路径和.exe路径
    作者:丶布布文章预览:......
  • [C++] 互斥锁(unique_lock、lock_guard)
    作者:丶布布......
  • [C++] 强制类型转换(dynamic_cast和dynamic_Pointer_cast)
    作者:丶布布1、指引或者引用的向上转换,向下转换例如基类Father,Son继承Father,派生类Son.。Father—>Son则为向下转换,Son—>Father则为向上转换。向上转换为隐士转换,向下转换需要dynamic_cast或者c的转换方式。向上转换:structFather{//基类Father};structSon:Father{//......
  • [C++ 从入门到精通] 5.迭代器精彩演绎、失效分析及弥补、实战
    作者:丶布布文章预览:一.迭代器简介二.容器的迭代器类型三.迭代器begin()/end()操作,反向迭代器rbegin()/rend()操作四.迭代器相关操作五.constiterator迭代器5.1.cbegin()和cend()操作六.迭代器失效及弥补6.1.灾难程序演示七.范例演示7.1用迭代器遍历string数据7.2vect......
  • [C++从入门到精通] 10.回顾类内初始化、默认构造函数、=default
    ......
  • [C++ 从入门到精通] 6.static_cast、dynamic_cast等显示类型转换
    作者:丶布布文章预览:一.隐式类型转换二.显式类型转换(强制类型转换)static_cast显示转换dynamic_cast显示转换const_cast显示转换reinterpret_cast显示转换三.总结一.隐式类型转换含义:隐式类型转换:系统自动进行,不需要开发人员介入。intm=3+45.6;//48因为返回的int型......
  • [C++ 从入门到精通] 带你彻了解C++中String类型的用法
    作者:丶布布文章预览:一.C++基本变量类型二.String对象的定义和初始化三.String对象的操作一.C++基本变量类型基本类型:int、double等。复合类型:引用、指针、const等。标准库类型:string(可变长字符串的处理)、vector(一种集合或容器的概念)、迭代器。对于字符串,在现实生活中,string......
  • C++ Qt开发:Charts绘图组件概述
    Qt是一个跨平台C++图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍QCharts二维绘图组件的常用方法及灵活运用。QtCharts提供了一个强大且易于使用的工具集,用于在......