【C++深度剖析教程5】C++中类的静态成员函数

  • 学习交流加(可免费帮忙下载CSDN资源):
  • 个人微信: liu1126137994
  • 学习交流资源分享qq群1(已满): 962535112
  • 学习交流资源分享qq群2(已满): 780902027
  • 学习交流资源分享qq群3:893215882

在上一篇文章中我们讲了C++中类的静态成员变量,用类的静态成员变量实现了统计程序运行期间的某个类的对象的数目(不清楚的可以点击连接查看上一篇文章 C++中类的静态成员变量)。

我们回顾一下客户的需求:

  • 统计在程序运行期间某个类的对象的数目
  • 保证程序的安全性(不能使用全局变量)
  • 随时可以获取当前对象的数目(完成了么?)

看当时的代码:

#include <stdio.h>class Test
{
private:static int cCount;
public:Test(){cCount++;}~Test(){--cCount;}int getCount(){return cCount;}
};int Test::cCount = 0;Test gTest;int main()
{Test t1;Test t2;printf("count = %d\n", gTest.getCount());printf("count = %d\n", t1.getCount());printf("count = %d\n", t2.getCount());Test* pt = new Test();printf("count = %d\n", pt->getCount());delete pt;printf("count = %d\n", gTest.getCount());return 0;
}

很明显,我们获取对象的数目是需要调用getCount这个函数,每次调用都需要某一个对象来调用,比如:gTest.getCount(),那么问题来了,如果整个程序的对象的个数为0呢?那么岂不是没法调用getCount这个函数,也就没法知道对象的个数(别人是不知道你的对象的个数为0的)?

可不可以这样呢?我把静态成员变量cCount变为public,然后直接让Test(作用域调用)这个类来调用?先上一波代码看看:

#include <stdio.h>class Test
{
public:static int cCount;
public:Test(){cCount++;}~Test(){--cCount;}int getCount(){return cCount;}
};int Test::cCount = 0;int main()
{printf("count = %d\n", Test::cCount);//Test::cCount = 1000;//printf("count = %d\n", Test::cCount);return 0;
}

此代码与上面的代码的不同的是cCount变量变为public便于Test(作用域访问)类调用,没有任何的对象了,那么编译运行,输出结果应该是:
count = 0

说明这样做,符合了我们的需求了。但是,不要高兴的太早了,我们这样真的可以么?加入我把代码中的被注释的那两行加上(下面这两行):

     Test::cCount = 1000;printf("count = %d\n", Test::cCount);

再次运行会发生什么呢?我们编译运行,结果输出为:

 count = 0count = 1000

那么多问题来了,客户现在懵逼了,他会以为对象的个数有1000个,所以,这也是一个大的Bug啊,从本上讲,这样做也是无法满足客户的需求的,而且将cCount变为public,本身就是无法保证静态成员变量的安全性,我们需要什么?

  • 不依赖对象就可以访问静态成员变量
  • 必须保证静态成员变量的安全性
  • 方便快捷得获取静态成员变量的值

那么静态成员函数就要出马了:
静态成员函数的定义:
直接通过static关键字修饰成员函数即可

为了便于理解,我们先上一段代码来理解一下静态成员函数的性质:

#include <stdio.h>class Demo
{
private:int i;
public:int getI();static void StaticFunc(const char* s);static void StaticSetI(Demo& d, int v);
};int Demo::getI()
{return i;
}void Demo::StaticFunc(const char* s)
{printf("StaticFunc: %s\n", s);
}void Demo::StaticSetI(Demo& d, int v)
{d.i = v;
}int main()
{Demo::StaticFunc("main Begin...");Demo d;d.StaticSetI(d, 20);printf("d.i = %d\n", d.getI());Demo::StaticSetI(d, 10);printf("d.i = %d\n", d.getI());Demo::StaticFunc("main End...");return 0;
}

以上代码运行的结果为:

StaticFunc: main Begin...
d.i = 20
d.i = 10
StaticFunc: main End...

由代码看到两个静态成员函数:

static void StaticFunc(const char* s);
static void StaticSetI(Demo& d, int v);

类调用静态成员函数:

Demo::StaticFunc("main Begin...");

对象调用静态成员函数:

d.StaticSetI(d, 20);

可以看出静态成员函数的性质大体如下:

  • 静态成员函数是类中特殊的成员函数
  • 静态成员函数属于整个类所有
  • 可以通过类名(作用域访问)直接访问公有静态成员函数
  • 可以通过对象名访问公有静态成员函数

而且通过这段代码:

void Demo::StaticSetI(Demo& d, int v)
{d.i = v;
}

我么可以看出,静态成员函数,没有直接调用变量i,而是通过对象来间接调用变量i,这说明什么呢?说明:静态成员函数不能访问普通成员变量(函数),需通过对象间接访问成员变量(函数)
下面做一个表格来对比一下静态成员函数与普通成员函数的区别:
在这里插入图片描述

好了,理解了静态成员函数,我们也应该来解决客户的需求了吧:直接上代码:

#include <stdio.h>class Test
{
private:static int cCount;
public:Test(){cCount++;}~Test(){--cCount;}static int GetCount(){return cCount;}
};int Test::cCount = 0;int main()
{printf("count = %d\n", Test::GetCount());Test t1;Test t2;printf("count = %d\n", t1.GetCount());printf("count = %d\n", t2.GetCount());Test* pt = new Test();printf("count = %d\n", pt->GetCount());delete pt;printf("count = %d\n", Test::GetCount());return 0;
}

运行结果为:

count = 0
count = 2
count = 2
count = 3
count = 2

分析: printf("count = %d\n", Test::GetCount());这段代码运行之前,没有创建对象,所以count = 0,

printf("count = %d\n", t1.GetCount());
printf("count = %d\n", t2.GetCount());

这两段代码运行之前已经创建了t1,t2这两个对象,所以都为:count = 2,

printf("count = %d\n", pt->GetCount());

这个运行之前又在堆空间创建了一个对象,并且让pt指针指向它,所以:count = 3

	delete pt;printf("count = %d\n", Test::GetCount());

在这两行先将pt指向的对象删除,所以最后是:count = 2

问题终于解决了!!!

总结:

  • 静态成员函数是类中的特殊的成员函数
  • 静态成员函数没有隐藏的this指针
  • 静态成员函数可以通过类名直接访问
  • 静态成员函数可以通过对象访问
  • 静态成员函数只能直接访问静态成员变量(函数),而不能直接访问普通成员变量(函数)

想获得各种学习资源以及交流学习的加我:
qq:1126137994
微信:liu1126137994
可以共同交流关于嵌入式,操作系统,C++语言,C语言,数据结构等技术问题!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/423355.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Lucene:基于Java的全文检索引擎简介

(转自http://hi.baidu.com/sz_xiaofeng/blog/item/7f3c33ed033444d1b31cb1b2.html)Lucene是一个基于Java的全文索引工具包。 基于Java的全文索引引擎Lucene简介&#xff1a;关于作者和Lucene的历史全文检索的实现&#xff1a;Luene全文索引和数据库索引的比较中文切分词机制简介…

eclipse 工程中使用引入maven项目遇到maven-resources-plugin:2.6 找不到

1.开始eclipse 配置本地库 首先是从maven 官网下载maven 组件 其次是配置 maven 环境和java 配置jdk 类似这里就不做介绍了 配置完环境后修改\apache-maven-3.3.9\conf\settings.xml 中的<localRepository> 设置本地仓库 然后配置eclipse 下面图中执行较为重要&#xff…

移植uboot之修改代码支持NorFlash记录

学习交流加 个人qq&#xff1a; 1126137994个人微信&#xff1a; liu1126137994学习交流资源分享qq群&#xff1a; 962535112 今天我们的任务是修改uboot源码支持NorFlash。 上两篇关于uboot移植的文章&#xff0c;我们修改了uboot源代码&#xff0c;支持了串口的输出&#xff…

保持一颗好学之心

保持一颗好学之心 初见这个题目&#xff0c;许多人可能会对自己相当满意&#xff1a;“我还是很好学的”。真的是这样吗&#xff1f;个人之见&#xff0c;有不少人其实并不像他们想象的那么好学&#xff0c;尤其是那些有了一定经验&#xff0c;在某些方面有些过人之处的“聪明”…

Vue.js 学习

后端和数据库角色&#xff0c;确参加了前端培训&#xff0c;哪就总结一下&#xff1a;后续继续更新 1.首先是vue.js 与jquery 的比较 vue.js 是采用数据和dom元素分类&#xff0c;采用的VMMV 模式 V view 视图 M Model 存放数据&#xff0c;VM 在M和V 主要是处理一些业务逻辑…

移植uboot之修改代码支持NorFlash记录续集

接着上一篇文章写的内容&#xff08;上一篇文章链接&#xff1a;移植uboot之修改代码支持NORFLASH&#xff09;&#xff0c;上一篇结尾测试flash的擦除读写功能&#xff0c;结果无法写flash&#xff0c;卡在了这里&#xff1a; 前面已经擦除成功&#xff0c;这里写内容写不进…

C#开发终端式短信的原理和方法

本文示例源代码或素材下载 简介 没发过短信的年轻人肯定是属于那种受保护的稀有动物&#xff0c;通讯发达的今天短信已经成为人们交流的重要手段&#xff0c;其中也蕴含着巨大的市场和经济利益&#xff0c;掌握短信技术的人才也受到各大公司的追捧是目前职场上耀眼的明星。本文…

移植uboot之修改代码支持NorFlash记录续集二

先说一个事&#xff1a;我会在最后把移植好的uboot&#xff0c;内核&#xff0c;分别做一个补丁文件&#xff0c;以后如果用到相同的uboot以及内核都可以直接下载我这个补丁进行打补丁操作就可以直接用~ 上一个移植uboot续集&#xff0c;我们解决了无法写flash的问题&#xff…

Mysql function(函数)

1.mysql 拼接函数 1. 1CONCAT(string1,string2,…) 说明 : string1,string2代表字符串,concat函数在连接字符串的时候&#xff0c;只要其中一个是NULL,那么将返回NULL 1.2 CONCAT_WS(separator,str1,str2,...)说明 : string1,string2代表字符串,concat_ws 代表 conca…

【C++深度剖析教程6】C++之友元

这几天在复习数学考试&#xff0c;都没有学C&#xff0c;今天抽空来学一点。 什么是友元&#xff1f; 友元是C中的一种关系友元发生在函数与类之间或者类与类之间友元关系是单向的&#xff0c;不能传递 在具体讲解友元的性质之前&#xff0c;我们先来看看一个程序&#xff…

SpringAOP xml 方式和注解简单实现日志处理

1.首先是用注解方式捕捉Controller 层异常&#xff1a; 首先是引入aop 依赖的jar <!-- Spring AOP 日志管理需要导入的包 --><dependency><groupId>org.aspectj</groupId><artifactId>aspectjrt</artifactId><version>1.8.13</…

call stack and stack buffer overflow

http://en.wikipedia.org/wiki/Call_stack http://en.wikipedia.org/wiki/Stack_buffer_overflow Stack_buffer_overflow里提到的frame pointer 的位置不一样&#xff0c;不同的系统实现应该是不一样的。 运行时的栈是从高地址向低地址分配的&#xff0c;堆是从低地址向高地址…

谈一下我对如何设计微服务接口的理解和思考

微服务是一个独立运行、自带数据存储管理&#xff0c;对外提供接口的自治系统。微服务设计很关键的一点是微服务接口的设计。不同微服务经常是分配给不同的团队开发的&#xff0c;接口是各团队编程的契约。 下面只讨论微服务间接口的设计&#xff0c;至于微服务内部子模块间接…

【C++深度剖析教程7】C++之类中的函数重载

函数重载的回顾&#xff08;接上一篇文章&#xff09;&#xff1a; 函数重载的本质为相互独立的不同的函数C中通过函数名和函数参数确定函数调用无法直接通过函数名得到重载函数的入口地址函数重载必然发生在同一个作用域中 类中的成员函数可以进行重载 构造函数的重载普通成…

Linux 服务器远程控制三剑客Telnet、SSH 和 VNC 之 VNC

使用VNC服务实现远程控制Telnet和SSH服务只能实现基于字符界面的远程控制&#xff0c;如果要基于图形界面进行远程控制&#xff0c;可以借助免费的VNC来完成。VNC是VirtualNetworkComput-ing英文的缩写&#xff0c;它是一款优秀远程控制软件&#xff0c;类似Windows的终端服务。…

嵌入式Linux操作系统移植IMX6开发板之实现USB 自动挂载

学习交流加 个人qq&#xff1a; 1126137994个人微信&#xff1a; liu1126137994学习交流资源分享qq群&#xff1a; 962535112 本篇文章讲述如何实现USB自动挂载&#xff0c;U盘即插即用&#xff0c;不用手动挂载的方法&#xff0c;以及给出U盘自动挂载的原理。 目前做的IMX6开发…

C# 繁体,简体 互转

usingMicrosoft.VisualBasic; publicstaticstringTraditional2Simplified(stringstr) { //繁体转简体 return(Microsoft.VisualBasic.Strings.StrConv(str, Microsoft.VisualBasic.VbStrConv.SimplifiedChinese, 0)); } publicstaticstringSimplified…

【C++深度剖析教程8】C++的操作符重载的概念

之前学习了类的函数重载的概念&#xff0c;今天学习操作符重载的概念。在这之前我们先看一个例子&#xff1a; 上面是一个复数的加法&#xff0c;a为复数的实部&#xff0c;b为复数的虚部&#xff0c;在main函数里我想实现复数c1与c2的加法。很显然&#xff0c;正常的号操作符…

大数据开发者应该知道的分布式系统 CAP 理论

无论你是一个系统架构师&#xff0c;还是一个普通开发&#xff0c;当你开发或者设计一个分布式系统的时候&#xff0c;CAP理论是无论如何也绕不过去的。本文就来介绍一下到底什么是CAP理论&#xff0c;如何证明CAP理论&#xff0c;以及CAP的权衡问题。 CAP理论概述 CAP理论&a…

【C++深度剖析教程11】C++学习之编写代码实现复数类

今天&#xff0c;我来学习将复数的加减乘除以及比较运算&#xff0c;编写一个复数类&#xff0c;方便计算复数之间的运算。具体用的方法就是之前写过的操作符重载的概念来实现&#xff08;操作符重载的概念学习&#xff09;。 那么为了显得清晰&#xff0c;今天写的程序运用模块…