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

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

慕羽★

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值