C++中静态成员变量和普通成员变量、私有成员变量和公有成员变量的区别

        本文主要介绍和记录C++中静态成员变量和普通成员变量、私有成员变量和公有成员变量的区别,并给出相关示例程序,最后结合相关工程应用中编译报错给出报错原因及介绍思路

一、静态成员变量和普通成员变量

         C++中,静态成员变量和普通成员变量有一些重要的区别,如下所示:

1. 存储位置:


   普通成员变量: 每个类的对象都有自己的一份普通成员变量的拷贝,它们存储在对象的内存中。
   静态成员变量: 所有属于同一个类的对象共享同一份静态成员变量的拷贝,它存储在类的类体外,并且不依赖于类的实例。

2. 作用域:


   普通成员变量: 只有在类的实例化后,通过对象访问。
   静态成员变量: 可以通过类名直接访问,不需要创建类的实例。

3. 初始化:


  普通成员变量: 在每个对象被创建时进行初始化,可以在类的构造函数中进行。
  静态成员变量: 需要在类体外进行初始化,通常在类的实现文件中进行。

4. 生命周期:


   普通成员变量: 随着对象的创建而创建,随着对象的销毁而销毁。
    静态成员变量:从程序开始时创建,直到程序结束时销毁。

5. 访问权限:


    普通成员变量:可以是公有、私有或受保护的,根据访问修饰符的设置。
    静态成员变量: 也可以是公有、私有或受保护的,但由于可以通过类名直接访问,一般建议将其声明为私有,并提供公有的静态成员函数用于访问或修改。

6. 使用场景:


   普通成员变量: 通常用于描述对象的状态或属性。
   静态成员变量:通常用于描述属于整个类而非特定对象的属性,例如计数器、共享资源等。

        下面是一个简单的例子,演示了静态成员变量和普通成员变量的用法:

#include <iostream>

class MyClass {
public:
    int regularVar;        // 普通成员变量
    static int staticVar;  // 静态成员变量

    // 构造函数
    MyClass() {
        regularVar = 0;
    }

    // 静态成员函数,可以访问静态成员变量和其他静态成员函数
    static void staticFunction() {
        staticVar++;
    }
};

// 初始化静态成员变量
int MyClass::staticVar = 0;

int main() {
    MyClass obj1, obj2;

    obj1.regularVar = 10;
    obj2.regularVar = 20;

    // 访问普通成员变量,实例化后,通过对象访问
    std::cout << "Regular Variable of obj1: " << obj1.regularVar << std::endl;
    std::cout << "Regular Variable of obj2: " << obj2.regularVar << std::endl;

    // 访问静态成员变量,不需要实例化类的对象
    std::cout << "Static Variable: " << MyClass::staticVar << std::endl;

    // 调用静态成员函数
    MyClass::staticFunction();
    std::cout << "Static Variable after calling staticFunction: " << MyClass::staticVar << std::endl;

    return 0;
}

          这个程序创建了一个 MyClass 类,其中包含了一个普通成员变量 regularVar 和一个静态成员变量 staticVar。`regularVar`是普通成员变量,每个对象都有自己的副本。`staticVar` 是静态成员变量,所有对象共享同一个副本。

        在 main 函数中,创建了两个对象 obj1obj2,分别设置了它们的 regularVar 值。然后,分别通过类名和对象访问了静态成员变量和普通成员变量,并调用了静态成员函数来改变staticVar的值

        运行结果如下:

Regular Variable of obj1: 10
Regular Variable of obj2: 20
Static Variable: 0
Static Variable after calling staticFunction: 1

   

 二、私有成员变量和公有成员变量

        在C++中,私有成员变量和公有成员变量有以下主要区别:

1. 访问权限:


   - 私有成员变量: 只能在类的内部访问,外部代码无法直接访问。只有类的成员函数(包括私有成员函数和公有成员函数)可以访问私有成员。
   - 公有成员变量: 可以被类的外部代码直接访问,没有访问限制。

2. 封装性:


   - 私有成员变量:提供了更好的封装性,隐藏了类的实现细节,外部代码无法直接修改或访问私有成员。
   - 公有成员变量:破坏了封装性,外部代码可以直接修改公有成员,导致代码的不安全性和可维护性降低。

3. 安全性:


   - 私有成员变量: 提高了代码的安全性,防止外部代码意外地修改类的内部状态。
   - 公有成员变量:可能降低代码的安全性,因为外部代码可以直接修改类的公有成员。

4. 灵活性:


   - 私有成员变量: 允许类实现者更灵活地控制类的内部状态和行为,可以在类的内部进行适当的处理。
   - 公有成员变量: 提供了更直接的访问方式,但可能导致类的实现难以修改。

5. 继承和派生:


   - 私有成员变量:在派生类中不可直接访问基类的私有成员。
   - 公有成员变量:在派生类中可以直接访问基类的公有成员,但这同样可能导致破坏封装性。

        下面是一个简单的例子,演示了私有成员变量和公有成员变量的用法:

#include <iostream>

class Example {
private:
    int privateVar;  // 私有成员变量

public:
    int publicVar;   // 公有成员变量

    // 构造函数
    Example() {
        privateVar = 0;
        publicVar = 0;
    }

    // 成员函数访问私有成员
    void setPrivateVar(int value) {
        privateVar = value;
    }

    int getPrivateVar() const {
        return privateVar;
    }
};

int main() {
    Example obj;

    // 外部无法直接访问私有成员
    // obj.privateVar;  // 编译错误

    // 外部可以直接访问公有成员
    obj.publicVar = 42;

    // 调用成员函数访问私有成员
    obj.setPrivateVar(10);
    int privateValue = obj.getPrivateVar();

    // 输出结果
    std::cout << "Public Variable: " << obj.publicVar << std::endl;
    std::cout << "Private Variable: " << privateValue << std::endl;

    return 0;
}

        在上述示例中,`privateVar` 是私有成员变量,只能通过成员函数进行访问,而`publicVar` 是公有成员变量,可以直接在外部访问。

        运行结果如下:

Public Variable: 42
Private Variable: 10

 三、相关编译报错原因及解决方法

        1、编译报错内容如下:

/home/gly/catkin_ws/src/navigation-noetic-devel/rrt_star_global_planner-main/src/traj_optimizer.cpp:1066:9: error: invalid use of member ‘Trajectory_optimization::BsplineOptimizer::Opt_Storage’ in static member function
 1066 |         Opt_Storage.save_vector_T(opt_base_path,FN_2,time_consuming);
      |         ^~~~~~~~~~~
In file included from /home/gly/catkin_ws/src/navigation-noetic-devel/rrt_star_global_planner-main/src/traj_optimizer.cpp:1:
/home/gly/catkin_ws/src/navigation-noetic-devel/rrt_star_global_planner-main/include/rrt_star_global_planner/traj_optimizer.h:66:37: note: declared here
   66 |       Data_Storage::FileDataStorage Opt_Storage; //创建FileDataStorage类的实例,取名为Mpc_Storage
 

        2、报错原因分析:

        我们以第一个报错为例进行介绍,报错原因是在类中创建了普通成员Opt_Storage,然后尝试在类的静态成员函数 costFunctionCallback 中直接调用类的该普通成员Opt_Storage,导致报错

        因为,静态函数无法直接访问非静态成员!!!

        3、解决方案:

        有三种解决思路,第一种costFunctionCallback 设计成非静态成员函数,这样它就可以访问实例的成员变量。此时,在该函数中直接使用以下语句就不会产生报错了

Opt_Storage.save_vector_T(opt_base_path,FN_2,time_consuming);

       如果我们需要保留 costFunctionCallback函数为静态成员函数,则可以采用第二种方案,使用实例化的类的对象来调用该成员,此时,上述语句需要改写成以下的形式

//由于costFunctionCallback是静态成员函数,而静态函数无法直接访问非静态成员
//需要借助类的实例来访问
Trajectory_optimization::BsplineOptimizer temporary_object;
    
temporary_object.Opt_Storage.save_vector_T(temporary_object.opt_base_path,temporary_object.FN_2,time_consuming); 

        如果我们需要保留 costFunctionCallback函数为静态成员函数,除了上面的第二种方案,还有第三种解决方案,即将想要在costFunctionCallback函数中直接调用的相关成员,由普通成员更改为静态成员,并在类中声明,在类外对其进行初始化。

   最终,因为我需要保留costFunctionCallback函数为静态成员函数,且为了方便的通过修改类所在的h文件来对相关参数进行设定,不想采用类内声明,类外初始化的形式,所以放弃了第一种和第三种方案,采用了第二种方案,编译成功

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C语言指针详解(1)(能看懂字就能明白系列)文章超长,慢慢品尝

目录 1、内存和地址 2、指针简介 与指针相关的运算符&#xff1a; 取地址操作符&#xff08;&&#xff09; 解引用操作符&#xff08;间接操作符&#xff09;&#xff08;*&#xff09; ​编辑 指针变量的声明 指针变量类型的意义 指针的基本操作 1、指针与整数相加…

网申线上测评,要不要找人代做在线测评?

这是知乎上看来的问题&#xff0c;感触颇多&#xff0c;于是决定针对这个问题写个稿子&#xff0c;希望能帮助到更多人朋友。 原文如下&#xff1a;现在各大公司在招聘时通常都会采取网申发OT筛选的形式&#xff0c;但是由于难度较大&#xff0c;不少人会选择付钱找别人代做的方…

常见面试题-MySQL软删除以及索引结构

为什么 mysql 删了行记录&#xff0c;反而磁盘空间没有减少&#xff1f; 答&#xff1a; 在 mysql 中&#xff0c;当使用 delete 删除数据时&#xff0c;mysql 会将删除的数据标记为已删除&#xff0c;但是并不去磁盘上真正进行删除&#xff0c;而是在需要使用这片存储空间时…

uart控制led与beep

仲裁模块代码&#xff1a; // 外设控制模块&#xff0c;根据uart接收到的数据&#xff0c;控制led与beep的标志信号。 module arbit(input wire sys_clk ,input wire sys_rst_n ,input wire pi_flag …

交易者最看重什么?anzo Capital这点最重要!

交易者最看重什么&#xff1f;有人会说技术&#xff0c;有人会说交易策略&#xff0c;有人会说盈利&#xff0c;但anzo Capital认为Vishal 最看重的应该是眼睛吧&#xff01; 29岁的Vishal Agraval在9年前因某种原因失去了视力&#xff0c;然而&#xff0c;他的失明并未能阻…

【C#】类型转换-显式转换:括号强转、Parse法、Convert法、其他类型转string

目录 一、括号强转 1.有符号整型 2.无符号整型 3.浮点之间 4.无符号和有符号 5.浮点和整型 6.char和数值类型 7.bool和string是不能够通过 括号强转的 二、Parse法 1.有符号 2.无符号 3.浮点型 4.特殊类型 三、Convert法 1.转字符串 2.转浮点型 3.特殊类型转换…

R语言绘制精美图形 | 火山图 | 学习笔记

一边学习&#xff0c;一边总结&#xff0c;一边分享&#xff01; 教程图形 前言 最近的事情较多&#xff0c;教程更新实在是跟不上&#xff0c;主要原因是自己没有太多时间来学习和整理相关的内容。一般在下半年基本都是非常忙&#xff0c;所有一个人的精力和时间有限&#x…

Rockdb简介

背景 最近在使用flink的过程中&#xff0c;由于要存储的状态很大&#xff0c;所以使用到了rockdb作为flink的后端存储&#xff0c;本文就来简单看下rockdb的架构设计 Rockdb设计 Rockdb采用了LSM的结构&#xff0c;它和hbase很像&#xff0c;不过严格的说&#xff0c;基于LS…

【Linux】安全审计-audit

文章目录 一、audit简介二、开启auditd服务三、相关文件四、审计规则五、审计日志查询及分析附录1&#xff1a;auditctl -h附录2&#xff1a;systemcall 类型 参考文章&#xff1a; 1、安全-linux audit审计使用入门 2、audit详细使用配置 3、Linux-有哪些常见的System Call&a…

redis实战篇(2)

优惠卷秒杀 通过本章节&#xff0c;我们可以学会Redis的计数器功能&#xff0c; 结合Lua完成高性能的redis操作&#xff0c;同时学会Redis分布式锁的原理&#xff0c;包括Redis的三种消息队列 3、优惠卷秒杀 3.1 -全局唯一ID 每个店铺都可以发布优惠券&#xff1a; 当用户抢…

卷积神经网络(CNN)鲜花的识别

文章目录 前期工作1. 设置GPU&#xff08;如果使用的是CPU可以忽略这步&#xff09;我的环境&#xff1a; 2. 导入数据3. 检查数据 二、数据预处理1. 加载数据2. 可视化数据3. 再次检查数据4. 配置数据集 三、构建CNN网络四、编译五、训练模型六、模型评估 前期工作 1. 设置GP…

IP池大小重要吗?

我们在寻找靠谱的IP代理时也经常遇到一个问题&#xff0c;IP代理池是什么&#xff1f;大小有何影响。今天就来跟大家普及一下&#xff0c;IP代理池大小的是否重要&#xff1f; 一、IP代理池是什么&#xff1f; I\P代理池是一个存储大量代理服务器IP地址的集合。它是一个由多个…

【MMC/SD/SDIO】读写操作

SD 总线是基于命令和数据流&#xff0c;它们由一个开始 Bit 发起&#xff0c;由一个停止 Bit 结束。 Command&#xff1a;命令开始一个操作。命令由 Host 驱动&#xff0c;或者给单卡&#xff08;寻址命令&#xff09;&#xff0c;或者给所有连接的卡&#xff08;广播命令&…

【操作系统】虚拟内存浅析

文章目录 虚拟内存的概念虚拟内存的实现请求分页存储管理缺页中断机构地址变换机构页面置换算法页面分配策略调入页面的时机 虚拟内存的概念 所谓的虚拟内存&#xff0c;是具有请求调入和置换功能&#xff0c;从逻辑上对内存容量加以扩充的一种存储器系统。他的组成如下&#…

微软 Gradle 强强联手,Gradle 构建服务器正式开源!

作者&#xff1a;Nick Zhu - Senior Program Manager, Developer Division At Microsoft 排版&#xff1a;Alan Wang Gradle 构建服务器 (Build Server for Gradle) 在九月份&#xff0c;我们宣布 Microsoft 和 Gradle 联手探索了一种基于 Build Server Protocol&#xff08;B…

【SpringMvc】SpringMvc +MyBatis整理

&#x1f384;欢迎来到边境矢梦的csdn博文&#x1f384; &#x1f384;本文主要梳理 Java 框架 中 SpringMVC的知识点和值得注意的地方 &#x1f384; &#x1f308;我是边境矢梦&#xff0c;一个正在为秋招和算法竞赛做准备的学生&#x1f308; &#x1f386;喜欢的朋友可以关…

为什么Go是后端开发的未来

近年来&#xff0c;Go 编程语言的流行度迅速增加。Go 最初由 Google 开发&#xff0c;迅速成为后端开发中最受欢迎的语言之一&#xff0c;特别是在分布式系统和微服务的开发中。本文将讨论为什么 Go 是后端开发的未来。 Go 简介 Go&#xff0c;又称为 Golang&#xff0c;是由…

【图数据库实战】HugeGraph架构

一、概述 作为一款通用的图数据库产品&#xff0c;HugeGraph需具备图数据的基本功能&#xff0c;如下图所示。HugeGraph包括三个层次的功能&#xff0c;分别是存储层、计算层和用户接口层。 HugeGraph支持OLTP和OLAP两种图计算类型&#xff0c;其中OLTP实现了Apache TinkerPop3…

如何从Android手机恢复已删除的联系人

联系人应该是最重要的信息之一。 如果您不小心从Android手机中删除了联系人&#xff0c;该怎么办&#xff1f; 如果不容易找回丢失的联系人&#xff0c;您可以使用奇客数据恢复安卓版。 从Android的手机中恢复已删除的联系人 只需删除Android联系人&#xff0c;然后您就可以通…

【Java 进阶篇】揭秘 JQuery 广告显示与隐藏:打造令人惊艳的用户体验

在当今互联网时代&#xff0c;广告已经成为网页中不可忽视的一部分。然而&#xff0c;如何通过巧妙的交互设计&#xff0c;使广告既能吸引用户的眼球&#xff0c;又不会给用户带来干扰&#xff0c;成为了许多前端开发者需要思考的问题之一。在这篇博客中&#xff0c;我们将深入…