静态成员的详细讲解

静态成员(Static Members)是一种特殊的类成员,它们与类本身而不是与任何具体的对象实例相关联。静态成员可以是静态变量或静态函数,允许不同的对象共享数据和行为。

静态成员的特性

共享性

所有类的实例(对象)共享同一个静态成员,静态成员在所有对象之间是唯一的,因此在内存中只存在一份。

访问方式

静态成员可以通过类名直接访问,无需创建类的实例,但是非静态成员函数不能用类名直接访问。静态成员也可以通过对象访问,但这不是推荐的方式,因为它不清晰。

class Point
{
public:	void init(){  }static void output(){}
};int main()
{Point::init();  	//出错Point::output();
}//错误,不能用类名直接访问非静态成员函数,显示:“Point::init”: 调用非静态成员函数需要一个对象//把main()改一下如下:
int main()
{Point pt;pt.init();  //正确,可以用类对象进行访问pt.output();
}

生命周期

静态成员的生命周期与程序运行周期一致。在程序运行期间,它们在静态存储区分配内存。

定义和声明

静态成员变量需要在类外定义(初始化),即使在类内部声明了它们。

#include <iostream>
using namespace std;
class Point
{
public:	Point(){  m++;}~Point(){m--;}static void output(){cout<<m;}
private:static int m;
};
int main()
{Point pt;pt.output();
}

出错,这是因为类的静态成员变量在使用前必须先初始化。在main()函数前加上:

int Point::m = 0;
//输出:1

静态成员函数

静态成员函数只能访问静态成员变量,不能访问非静态成员变量,因为它们无法通过 this 指针访问对象的属性

在类的静态成员函数中使用类的非静态成员:

#include <iostream>
using namespace std;
class Point
{
public:	void init(){  }static void output(){cout<<n;;}
private:int n;
};
int main()
{Point pt;pt.output();
}

错误	C2597	对非静态成员“Point::n”的非法引用

出错,因为静态成员函数属于整个类,在类实例化对象之前就已经分配空间了,而类的非静态成员必须在类实例化对象后才有内存空间,所以这个调用就出错了。

在类的非静态成员函数中使用类的静态成员;

class Point
{
public:	void init(){  output();}static void output(){}
};
int main()
{Point pt;pt.output();
}

正确,类的非静态成员函数可以调用用静态成员函数,但反之不能。因为静态成员没有this指针,而非静态成员有this指针(this指针的作用之一:区分对象的成员与其他局部变量(会出个文章详细讲解this指针))

静态成员的作用

共享信息

静态成员变量用于存储所有类实例共享的信息(如计数器),如记录创建的对象数量,或者共享配置设置。

实现类级别的行为

静态成员函数可以用于写不依赖于特定对象的类方法,这在需要进行类级别的操作时非常有用。

保持状态

可以在多个对象间共享状态,提供更高效的数据管理。

示例

#include <iostream>  
using namespace std;  class Box {  
public:  // 静态成员变量  static int objectCount;  // 声明静态成员变量  Box() {  // 每当创建一个 Box 对象时,objectCount 增加  objectCount++;  }  // 静态成员函数  static int getObjectCount() {  return objectCount;  // 返回当前对象数量  }  
};  // 在类外定义静态成员变量  
int Box::objectCount = 0;  int main() {  Box box1;  // 创建第一个 Box 对象  Box box2;  // 创建第二个 Box 对象  // 通过类名访问静态成员函数  cout << "Total Box objects created: " << Box::getObjectCount() << endl;  // 输出: 2  return 0;  
}

注意事项

静态成员变量必须初始化

静态成员变量只能在类外定义和初始化,且只能定义一次。

非静态函数不能直接访问静态成员函数

非静态成员函数可以访问静态成员数据,但静态成员函数无法访问非静态成员变量或函数,因为静态函数不具有 this 指针。

影响设计:过多使用静态成员可能导致代码难以测试和维护,因为静态成员共享状态可能引入线程安全问题和不可预知的行为。

全局静态变量和静态成员函数

static全局变量与普通的全局变量有什么区别:

普通全局变量

非静态全局变量的作用域是整个源文件,当一个源程序由多个源文件组成时,它在各个源文件中都是有效的;作用域是整个程序。

int globalVar = 10; // 普通全局变量  void functionA() {  std::cout << "Global Var in functionA: " << globalVar << std::endl;  
}  void functionB() {  std::cout << "Global Var in functionB: " << globalVar << std::endl;  
}

静态全局变量 

静态成员变量作用域局限在一个源文件内,只能为该源文件内的函数公用,因此可以避免在其他源文件中引起错误。

static int staticGlobalVar = 20; // 静态全局变量  void functionC() {  std::cout << "Static Global Var in functionC: " << staticGlobalVar << std::endl;  
}

链接性 

普通全局变量

普通全局变量具有外部链接性,可以在多个源文件之间共享。其他源文件可以通过 extern 声明来访问它。

// file1.cpp  
int globalVar = 10; // 普通全局变量  // file2.cpp  
extern int globalVar; // 引用 file1.cpp 的普通全局变量

静态全局变量

静态全局变量具有内部链接性,仅在定义它的文件中可见。即使其他文件尝试引用它,也会导致链接错误。

存储持续性

普通全局变量

存储在程序的静态存储区(通常在数据段),生命周期从程序开始到结束,变量的值在程序的整个运行期间保持。

静态全局变量

同样存储在静态存储区,生命周期和普通全局变量相同,但其作用域仅限于定义它的文件。

示例

// file1.cpp  
#include <iostream>  int globalVar = 5; // 普通全局变量  
static int staticGlobalVar = 10; // 静态全局变量  void showVariables() {  std::cout << "globalVar: " << globalVar << std::endl; // 可以访问普通全局变量  std::cout << "staticGlobalVar: " << staticGlobalVar << std::endl; // 可以访问静态全局变量  
}// file2.cpp  
#include <iostream>  // extern int globalVar; // 可以访问 file1.cpp 中定义的普通全局变量,但不能访问静态全局变量  void anotherFunction() {  // std::cout << "staticGlobalVar: " << staticGlobalVar << std::endl; // 这会导致链接错误  
}

static函数和普通函数有什么区别:

静态函数

  • 静态成员函数是类的成员函数,但它不依赖于类的任何实例,可以通过类名直接调用。
  • 静态函数只能访问静态成员变量和其他静态成员函数,无法访问非静态成员变量和函数,因为它没有 this 指针。
class Example {  
public:  static void staticFunction() {  // 只能访问静态成员  }  
};  Example::staticFunction(); // 通过类名调用

普通函数

  • 普通成员函数依赖于一个对象实例,可以通过对象调用。
  • 普通函数能够访问所有成员变量(静态和非静态)以及其他成员函数,因为它们通过 this 指针定位到具体对象。
class Example {  
private:  int value;  
public:  void normalFunction() {  // 可以访问非静态成员 value  }  
};  Example obj;  
obj.normalFunction(); // 通过对象调用

 存储持续性

  • 静态函数

    • 静态成员函数的内存分配是在程序运行期间分配的,并在程序结束时释放。
    • 静态函数在所有对象之间共享,且在其类生命周期内存在一份。
  • 普通函数

    • 普通成员函数的存在与其包含的对象实例紧密相关,必须通过对象实例调用。

对象访问

  • 静态函数

    • 由于没有 this 指针,静态成员函数无法访问实例的成员变量和普通成员函数。
    • 使用静态函数通常用于执行一些与对象状态无关的操作,或者用于访问和修改静态成员。
  • 普通函数

    • 普通成员函数与具体对象关联,并通过 this 指针确保可以修改对象的状态。

适用场景

  • 静态函数

    • 用于实现类级别的操作,比如工厂方法、单例模式等。
    • 适用于执行与特定对象无关的功能,或者需要共享的状态管理。
  • 普通函数

    • 用于定义对象的行为,通常用来操作和修改对象的非静态数据。
    • 适合用于需要对象特定状态的功能。

示例

#include <iostream>  
using namespace std;  class Example {  
private:  static int staticValue;  int instanceValue;  public:  Example(int v) : instanceValue(v) {  staticValue++;  }  // 静态成员函数  static void displayStaticValue() {  cout << "Static Value: " << staticValue << endl;  }  // 普通成员函数  void displayInstanceValue() {  cout << "Instance Value: " << instanceValue << endl;  }  
};  // 静态成员变量初始化  
int Example::staticValue = 0;  int main() {  Example obj1(10);  Example obj2(20);  Example::displayStaticValue(); // 访问静态函数  obj1.displayInstanceValue();    // 访问普通成员函数  obj2.displayInstanceValue();    // 访问普通成员函数  return 0;  
}

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

蓝桥杯第22场小白入门赛2~5题

这场比赛开打第二题就理解错意思了&#xff0c;还以为只能用3个消除和5个消除其中一种呢&#xff0c;结果就是死活a不过去&#xff0c;第三题根本读不懂题意&#xff0c;这蓝桥杯的题面我只能说出的是一言难尽啊。。第四题写出来一点但是后来知道是错了&#xff0c;不会正解&am…

sagemaker中使用pytorch框架的DLC训练和部署cifar图像分类任务

参考资料 https://github.com/aws/amazon-sagemaker-examples/blob/main/sagemaker-python-sdk/pytorch_cnn_cifar10/pytorch_local_mode_cifar10.ipynbhttps://sagemaker.readthedocs.io/en/stable/frameworks/pytorch/using_pytorch.html 获取训练数据 # s3://zhaojiew-sa…

golang笔记8-函数

1. 基本函数 package mainimport "fmt"/*什么是函数&#xff1a;完成某一功能的程序指令的集合语法&#xff1a;func 函数名称(形参列表)(返回值类型列表){执行语句。。。返回值列表}注意事项&#xff1a;函数名&#xff1a;函数名首字母大写&#xff1a;可以被本包…

vite+vue3+ts编译vue组件后,编译产物中d.ts文件为空

一、前言 使用vue3vitets实现一个UI组件库&#xff0c;为了生成类型文件便于其他项目引用该组件库。根据推荐使用了vite-plugin-dts插件进行ts文件的生成 二、版本 组件版本vue ^3.5.12 vite ^5.4.10 vite-plugin-dts ^4.3.0 typescript ~5.6.2 三、问题描述 使用vitevi…

向量数据库FAISS之二:基础进阶版

基础 1.评价类型和距离 1.METRIC_L2 Faiss 使用了欧几里得 (L2) 距离的平方&#xff0c;避免了平方根。 这仍然与欧几里德距离一样单调&#xff0c;但如果需要精确距离&#xff0c;则需要结果的额外平方根。 2.METRIC_INNER_PRODUCT 这通常用于推荐系统中的最大内积搜索。…

家庭网络常识:猫与路由器

这张图大家应该不陌生——以前家庭网络的连接方式。 图1 家庭网络连接示意图 来说说猫/光猫&#xff1a; 先看看两者的图片。 图2 猫 图3 光猫 这个东西因为英文叫“modem”&#xff0c;类似中文的“猫”&#xff0c;所以简称“猫”。 猫和光猫的区别就是&#xff0c;一…

华三预赛学习笔记(每日编辑,复习完为止)

知识点分布 路由交换技术基础 计算机网络基本概念 计算机网络基本概念&#xff1a; 很多电脑和设备通过电线或无线信号连在一起&#xff0c;可以互相“说话”和“分享东西” 网络的主要形式和发展历程&#xff1a; 诞生阶段-最早的计算机网络是以单个计算机为中心的联机系统-终…

技术速递|Microsoft.Extensions.VectorData 预览版简介

作者&#xff1a;Luis Quintanilla - 项目经理 排版&#xff1a;Alan Wang 我们很高兴推出 Microsoft.Extensions.VectorData.Abstractions 库&#xff0c;该库现已提供预览版。 正如 Microsoft.Extensions.AI 库为使用 AI 服务提供了一个统一层一样&#xff0c;此包为 .NET 生…

第5章-总体设计 5.3 硬件架构设计

5.3 硬件架构设计 1.哪些类型的产品需要架构设计&#xff1f;2.硬件架构师到底做什么&#xff1f;&#xff08;1&#xff09;理解需求和业务模型的情况。&#xff08;2&#xff09;背板设计&#xff0c;既需要考虑业务数据交换能力&#xff0c;也需要考虑子模块的管理监控能力。…

图像/文字差异类型验证码识别 无需训练

某像差异在个别全家桶验证方便有使用&#xff0c;对于这种验证码类型如下&#xff1a; 首先还是目标检测&#xff0c;直接用 dddd 自带的detection 就足够了。 特征提取 其次经过观察&#xff0c;差异答案与其他三个无非就是颜色&#xff0c;字体&#xff0c;方向&#xff0c…

新华三H3CNE网络工程师认证—生成树协议

新华三H3CNE网络工程师认证本节讲解生成树协议&#xff0c;关于生成树协议&#xff0c;提到生成树协议&#xff0c;这个时候不得不提到另外一个概念叫二层环路。二层环路导致的原因是交换机的转发机制导致的&#xff0c;本博客将分析这个机制导致这个问题的原因。 文章目录 一…

使用ai工具探究论文的工作流(阅读一个EEG的cnn-lstm文献(2021))

文章目录 李沐老师的方法论第一遍&#xff1a;做海选第二遍&#xff1a;对相关论文进行精选第三遍&#xff1a;重点研读 AI是怎么分析一个文章的标题&#xff08;Title&#xff09;和关键词摘要&#xff08;Abstract&#xff09;分析引言&#xff08;Introduction&#xff09;梳…

Scala的Array习题

答案&#xff1a;CBBBB import scala.collection.mutable.ArrayBuffer //1 case class DreamItem(content:String,var isDone:Boolean,deadline:String,var order:Int) object p5 {def main(args: Array[String]): Unit {//2val dreamListArrayBuffer[DreamItem]()//梦想清单/…

深度学习的实践层面

深度学习的实践层面 设计机器学习应用 在训练神经网络时&#xff0c;超参数选择是一个高度迭代的过程。我们通常从一个初步的模型框架开始&#xff0c;进行编码、运行和测试&#xff0c;通过不断调整优化模型。 数据集一般划分为三部分&#xff1a;训练集、验证集和测试集。常…

TPU-MLIR 总览

TPU-MLIR 总览 &#x1f4a1;深度学习编译器可以实现一次性代码开发和重用各种计算能力处理器的目标 ## 项目简介&#xff1a; TPU-MLIR 是 AI 芯片的 TPU 编译器工程。该工程提供了一套完整的工具链, 其可以将不同框架下预训练的神经网络, 转化为可以在算能 TPU 上高效运算的…

Vue3 + Vite 项目引入 Typescript

文章目录 一、TypeScript简介二、TypeScript 开发环境搭建三、编译方式1. 自动编译单个文件2. 自动编译整个项目 四、配置文件1. compilerOptions基本选项严格模式相关选项&#xff08;启用 strict 后自动包含这些&#xff09;模块与导入相关选项 2. include 和 excludeinclude…

苹果MacOS 调用自编译opencv的Dylib显示一个图片程序的步骤

前言 为了测试自编译的opencv库是否能在苹果MacOS系统下使用&#xff0c;需要写一个简单的测试程序。这个测试程序写起来不难&#xff0c;麻烦的是一些配置。网上的办法很多&#xff0c;里面因为版本的问题有一些坑。特此写了一个建立步骤&#xff0c;供大家参考。 1、新建一个…

AI赋能:高职院校实验实训教学如何拥抱人工智能浪潮?

随着信息技术的迅猛发展&#xff0c;人工智能技术已成为推动社会各行业转型升级的核心力量。它不仅在提升生产效率、优化管理流程、提高服务质量方面发挥着关键作用&#xff0c;也深刻影响着高职教育的专业发展和课程教学内容的改革。作为培养专业技术技能人才的摇篮&#xff0…

消费者行为学领域的顶级期刊

一、期刊 1.Journal of Consumer Research 2.Journal of Consumer Psychology 3.Journal of Research in Interactive Marketing 4.Journal of the Academy of Marketing Science 5.Tourism Management 下面是我整理的一个excel&#xff0c;大家按需丝我获取。 二、期刊&z…

STM32单片机CAN总线汽车线路通断检测-分享

目录 目录 前言 一、本设计主要实现哪些很“开门”功能&#xff1f; 二、电路设计原理图 1.电路图采用Altium Designer进行设计&#xff1a; 2.实物展示图片 三、程序源代码设计 四、获取资料内容 前言 随着汽车电子技术的不断发展&#xff0c;车辆通信接口在汽车电子控…