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

class="baidu_pl">
class="article_content clearfix">
class="htmledit_views">

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

class="img-center">

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

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

1. 存储位置:


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

2. 作用域:


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

3. 初始化:


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

4. 生命周期:


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

5. 访问权限:


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

6. 使用场景:


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

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

class="language-cpp">#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的值

        运行结果如下:

class="language-cpp">Regular Variable of obj1: 10
Regular Variable of obj2: 20
Static Variable: 0
Static Variable after calling staticFunction: 1

   

class="img-center">

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

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

1. 访问权限:


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

2. 封装性:


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

3. 安全性:


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

4. 灵活性:


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

5. 继承和派生:


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

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

class="language-cpp">#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` 是公有成员变量,可以直接在外部访问。

        运行结果如下:

class="language-cpp">Public Variable: 42
Private Variable: 10

class="img-center">

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

        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
 

class="img-center">

        2、报错原因分析:

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

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

        3、解决方案:

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

class="language-cpp">Opt_Storage.save_vector_T(opt_base_path,FN_2,time_consuming);

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

class="language-cpp">//由于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文件来对相关参数进行设定,不想采用类内声明,类外初始化的形式,所以放弃了第一种和第三种方案,采用了第二种方案,编译成功

class="img-center">

class="img-center">


http://www.niftyadmin.cn/n/5190192.html

相关文章

Matlab自学笔记二十四:字符串的关系运算和比较

1.关系运算 字符串的关系运算中&#xff0c;数字小于字母&#xff0c;大写字母小于小写字母&#xff1b;关系运算是按首字符进行的&#xff0c;首字符相同&#xff0c;按第二个&#xff0c;以此类推。程序示例如下&#xff1a; clear,clc names ["Steve Jobs" &q…

信号的机制——信号处理函数的注册

在 Linux 操作系统中&#xff0c;为了响应各种各样的事件&#xff0c;也是定义了非常多的信号。我们可以通过 kill -l 命令&#xff0c;查看所有的信号。 # kill -l1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP6) SIGABRT 7) SIGBUS …

读书笔记:彼得·德鲁克《认识管理》第22章 责任伦理

一、章节内容概述 管理者个人&#xff0c;哪怕是巨型公司的首席执行官&#xff0c;在20世纪也已经变得 与其他雇员一样籍籍无名、低调谦逊。但是&#xff0c;企业、学校、医院、政府 机构等各类组织的管理群体也成了现代组织社会的领导群体&#xff0c;他们同样 需要具备相应的…

基于黏菌算法优化概率神经网络PNN的分类预测 - 附代码

基于黏菌算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于黏菌算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于黏菌优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针对PNN神经网络的光滑…

2311rust到20版本更新

Rust1.9 Rust1.9中最大的变化是稳定了包括停止恐慌启动的展开过程方法的std::panic模块: use std::panic; let result panic::catch_unwind(|| {println!("hello!"); }); assert!(result.is_ok()); let result panic::catch_unwind(|| {panic!("oh no!"…

Kafka学习笔记(一)

目录 第1章 Kafka概述1.1 消息队列&#xff08;Message Queue&#xff09;1.1.1 传统消息队列的应用场景1.1.2 消息队列的两种模式 1.2 定义 第2章 Kafka快速入门2.1 安装部署2.1.1 集群规划2.1.2 jar包下载2.1.3 集群部署 2.2 Kafka命令行操作 第3章 Kafka架构深入3.1 Kafka工…

Unity中Shader雾效的实现方法二

文章目录 前言一、声明雾效所需要的内置变体二、在 v2f 中声明顶点传入片段中的雾效插值器三、 在顶点着色器中计算雾效采样四、在片元着色器中进行雾效颜色混合在这里插入图片描述 五、最终效果 前言 Unity中雾效的实现方法二&#xff0c;使用 Unity 自带的方法实现&#xff…

vue3 ts vite 主题色功能

开发工具&#xff1a;vue3 ts vite 如上图&#xff0c;选择个颜色整个变化&#xff0c;如下图 默认主题为绿色 切换成其它色。 这里面的颜色块&#xff0c;你也可以给个取器色组件&#xff0c;可切换成任意色。切换时主要执行下方的方法&#xff0c;有兴趣可自己研究下。 /…