C++类中静态变量和静态方法使用介绍

C++类中静态变量和静态方法使用介绍刷剑指offer第64题涉及到类内静态成员与方法的知识,有点模糊,找了两篇博客整理一下。转自:https://www.cnblogs.com/sixue/p/3997324.html    最近一直看c++相关的项目,但总是会被c++类中的静态成员变量与静态成员函数的理解感觉很是模糊,不明白为什么类中要是用静态成员变量.于是在网上搜集了一些资料,自己再稍微总结下。静态成员的概…

大家好,又见面了,我是你们的朋友全栈君。

刷剑指offer第64题涉及到类内静态成员与方法的知识,有点模糊,找了两篇博客整理一下。

C++类中静态变量和静态方法使用介绍

转自:https://www.cnblogs.com/sixue/p/3997324.html

       最近一直看c++相关的项目,但总是会被c++类中的静态成员变量与静态成员函数的理解感觉很是模糊,不明白为什么类中要是用静态成员变量.于是在网上搜集了一些资料,自己再稍微总结下。

静态成员的概念:

       静态类中的成员加入static修饰符,即是静态成员.可以直接使用类名+静态成员名访问此静态成员,因为静态成员先于类的声明而存在于内存,也可以根据类声明的对象来访问.而非静态成员必须实例化之后才会分配内存.

非静态成员的概念:

      所有没有加static的成员都是非静态成员.而类被实例化后,可以通过实例化的类名进行访问.非静态成员的生存期决定于该类的生存期.而静态成员不存在生产期的问题,因为它始终驻留在内存.

 

分两个方面来总结,面向过程与面向对象.

一:面向过程中的static关键字

1.静态全局变量

定义全局变量前,加上关键字static,该变量就被定义成了一个静态全局变量.

特点:

  • 该变量在全局数据区分配内存.
  • 初始化:如果不是显示初始化,那么将被隐式初始化为0.
  • 访变量只在本文件可见,即应该为定义之处开始到本文件结束.

程序在内存中一般分为四个区域:

  • 代码区
  • 全局数据区
  • 堆区
  • 栈区

一般程序由new产生的动态数据放在堆区,函数内部的自动变量放在栈区.自动变量一般会随着函数的退出而释放空间,静态数据(即使是函数内部的静态局部变量)都存放在全局数据区.因此它们并不会随着函数的退出而释放空间.

 static int n;//定义静态全局变量

改为:  int n;//定义全局变量

区别:

  静态全局变量不能被其他文件所用.因而其他文件可以定义相同名字的变量,而不会发生冲突.

例子:

//Example
//File 1
#include <iostream>
void fn();

static int n;//定义静态全局变量(只能在本文件中使用)
void main(){
   n=20;
   cout<<n<<endl;
   fn();
}


//File 2
#include <iostream>
extern int n;(可在别的文件中引用这个变量)
void fn(){
    n++;
    cout<<n<<endl;
}//编译并运行Example,就会发现上述代码分别通过编译,但Link时会出错.

如果将static int n改为 :int n;
再次编译运行程序,就不会出错.

2.静态局部变量

 在局部变量前加上static 关键字,就定义了静态局部变量.

特点:

  •   该变量在全局数据区分配内存.
  •   初始化时:如果不是显示初始化,那么将隐式初始化为0.
  •   它始终驻留在全局数据区,直到程序结束.但其作用域为局部作用域.当定义它的函数或语句块时,其作用域随之结束.

3.静态函数:在函数的返回类型前加上static关键字.

特点:

静态函数与普通函数不同,它只能在声明它的文件当中可见,不能被其他文件可用.

 

二:面向对象的static关键字

1.静态数据成员

在类中数据成员的声明前加上static,该成员是类的静态数据成员.

例子:

//example 2
#include <iostream>

class MyClass{
public:
     MyClass(int a,int b,int c);
     void GetSum();

private:
    int a,b,c;
    static int sum;//声明静态数据成员
};

int MyClass::sum=0;//定义并初始化静态数据成员

 

 

特点:

对于非静态数据成员,每个类对象都有自己的拷贝.而静态数据成员被当做是类的成员,无论这个类被定义了多少个,静态数据成员都只有一份拷贝,为该类型的所有对象所共享(包括其派生类).所以,静态数据成员的值对每个对象都是一样的,它的值可以更新.

因为静态数据成员在全局数据区分配内存,属于本类的所有对象共享,所以它不属于特定的类对象,在没有产生类对象前就可以使用.

 

2.静态成员函数

      与普通的成员函数相比,静态成员函数由于不是与任何的对象相联系,因此它不具有this指针.从这个意义上来说,它无法访问属于类对象的非静态数据成员,也无法访问非静态成员函数,只能调用其他的静态成员函数.

 

转自:https://www.cnblogs.com/ppgeneve/p/5091794.html

静态成员的提出是为了解决数据共享的问题。实现共享有许多方法,如:设置全局性的变量或对象是一种方法。但是,全局变量或对象是有局限性的。这一章里,我们主要讲述类的静态成员来实现数据的共享。

静态数据成员

  在类中,静态成员可以实现多个对象之间的数据共享,并且使用静态数据成员还不会破坏隐藏的原则,即保证了安全性。因此,静态成员是类的所有对象中共享的成员,而不是某个对象的成员。

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

静态数据成员的使用方法和注意事项如下:

  1、静态数据成员在定义或说明时前面加关键字static。//静态变量的定义

  2、静态成员初始化与一般数据成员初始化不同。静态数据成员初始化的格式如下:

    <数据类型><类名>::<静态数据成员名>=<值>  //静态变量的初始化

这表明:

       (1) 初始化在类体外进行,而前面不加static,(这点需要注意)以免与一般静态变量或对象相混淆。

  (2) 初始化时不加该成员的访问权限控制符private,public等。

  (3) 初始化时使用作用域运算符来标明它所属类,因此,静态数据成员是类的成员,而不是对象的成员。

  3、静态数据成员是静态存储的,它是静态生存期,必须对它进行初始化。

  4、引用静态数据成员时,采用如下格式:

   <类名>::<静态成员名>   //静态变量的使用方式

  如果静态数据成员的访问权限允许的话(即public的成员),可在程序中,按上述格式来引用静态数据成员。

下面举一例子,说明静态数据成员的应用:

​
class StaticTest
{
public:
    StaticTest(int a, int b, int c);
    void GetNumber();
    void GetSum();
    static void f1(StaticTest &s);
private:
    int A, B, C;
    static int Sum;
};



#include "StaticTest.h"
#include <iostream>
using namespace std;

int StaticTest::Sum = 0;//静态成员在此初始化

StaticTest::StaticTest(int a, int b, int c)
{
    A = a;
    B = b;
    C = c;
    Sum += A + B + C;
}

void StaticTest::GetNumber()
{
    cout << "Number = " << endl;
}

void StaticTest::GetSum()
{
    cout << "Sum = " << Sum <<endl;
}

void StaticTest::f1(StaticTest &s)
{
    
    cout << s.A << endl;//静态方法不能直接调用一般成员,可以通过对象引用实现调用
    cout << Sum <<endl;
}

#include "StaticTest.h"
#include <stdlib.h>


int main(void)
{
    StaticTest M(3, 7, 10), N(14, 9, 11);
    M.GetNumber();
    N.GetSum();
    M.GetNumber();
    N.GetSum();
    StaticTest::f1(M);
    system("pause");
    return 0;
}

​

注意,static成员的初始化要在实现中进行,不能在头文件进行。

从输出结果可以看到Sum的值对M对象和对N对象都是相等的。这是因为在初始化M对象时,将M对象的三个int型数据成员的值求和后赋给了Sum,于是Sum保存了该值。在初始化N对象时,对将N对象的三个int型数据成员的值求和后又加到Sum已有的值上,于是Sum将保存另后的值。所以,不论是通过对象M还是通过对象N来引用的值都是一样的,即为54,s.A=3。

静态成员函数

  静态成员函数和静态数据成员一样,它们都属于类的静态成员,它们都不是对象成员。因此,对静态成员的引用不需要用对象名。

  在静态成员函数的实现中不能直接引用类中说明的非静态成员,可以引用类中说明的静态成员(这点非常重要)。如果静态成员函数中要引用非静态成员时,可通过对象来引用。从中可看出,调用静态成员函数使用如下格式:<类名>::<静态成员函数名>(<参数表>);

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/140544.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • DM8168 GPIO驱动与測试程序

    DM8168 GPIO驱动与測试程序

    2021年11月29日
  • ISP举例_low input lag

    ISP举例_low input lag  从2000年9月底摄像头首次出现在手机上算起,到如今成为诸多智能设备不可或缺的一部分,便携式手机摄像头已经走过了18年的发展历程。随着手机智能化、轻薄化的发展进程,其搭载的摄像头也随之发生了变化,但基本结构并未有太大的改变。通常而言,一个摄像头硬件应包含以下五个部分:外壳(Housing)或者镜头固定物(LensHolder)、镜头(Lens)、红外截止滤波片(IR-cutfilter…

    2022年10月23日
  • 启动Redis报错:Could not create Server TCP listening socket *:6379: bind: Address already in use–解决办法

    启动Redis报错:Could not create Server TCP listening socket *:6379: bind: Address already in use–解决办法最后一句提示:6379地址已经在使用(6379是redis默认的端口)如图我自己输入指令./redis-server显示Redis已经开启服务1)正常解决方法三部①通过指令找到redis进程,查看所有关于它的进程详情。ps-ef|grefredisroot308610Apr24?00:00:07./bin/redis-…

  • 第一范式,第二范式,第三范式,BCNF范式理解

    第一范式,第二范式,第三范式,BCNF范式理解第一范式、第二范式、第三范式参考了https://www.zhihu.com/question/24696366https://www.cnblogs.com/lca1826/p/6601395.html基础知识实体:现实世界中客观存在并可以被区别的事物。比如“一个学生”、“一本书”、“一门课”等等。值得强调的是这里所说的“事物”不仅仅是看得见摸得着的“东西”,它也…

  • IC基础(一):异步FIFO[通俗易懂]

    IC基础(一):异步FIFO[通俗易懂]今天看别人的博客研究了一天的异步FIFO,中遇到了很多问题。很多人可能有过这样的经历,当你研究一个东西,可能你当时很清楚你是怎么想的,但是过后就忘记了当时的思路了。因此我写博客的主要目的就是为了回头查阅方便。IC基础可能会写很多篇,本篇异步FIFO就是此系列的第一篇。…

  • 线性代数的消元法_高斯消元法例题

    线性代数的消元法_高斯消元法例题1.消元的思想针对下面的方程,我们无法直接得到方程的解。$$\begin{alignedat}{2}&x\space\space&2&y\space=\space

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号