分享

APM(三):C++基础知识

 netouch 2024-06-28

一、代码


在正式阅读APM源码之前,了解C++的基础语法是必须的。以下抽取 AP_InertialSensor.h 文件的部分内容,以此说明C++基本语法。

class AP_InertialSensor : AP_AccelCal_Client
{
    friend class AP_InertialSensor_Backend;

public:
    AP_InertialSensor();
    /* Do not allow copies */
    AP_InertialSensor(const AP_InertialSensor &other) = delete;
    AP_InertialSensor &operator=(const AP_InertialSensor&) = delete;

    static AP_InertialSensor *get_singleton();
    
    enum Gyro_Calibration_Timing {
        GYRO_CAL_NEVER = 0,
        GYRO_CAL_STARTUP_ONLY = 1
    };
    
    void init(uint16_t sample_rate_hz);

    const Vector3f     &get_gyro(uint8_t i) const { return _gyro[i]; }
    const Vector3f     &get_gyro(void) const { return get_gyro(_primary_gyro); }

    Gyro_Calibration_Timing gyro_calibration_timing();
    
    static const struct AP_Param::GroupInfo var_info[];
    
    AuxiliaryBus *get_auxiliary_bus(int16_t backend_id, uint8_t instance);

    class BatchSampler {
    public:
    	...
    private:
    	...
    };
    BatchSampler batchsampler{*this};

private:
    void _start_backends();
	static AP_InertialSensor *_singleton;
    struct {
        float delta_time;
    } _hil {};
};

namespace AP {
    AP_InertialSensor &ins();
};

以下分成几个小段,依次解释。


二、语法解释


class AP_InertialSensor : AP_AccelCal_Client
  1. 定义了一个类 AP_InertialSensor;
  2. AP_InertialSensor继承了AP_AccelCal_Client,且是私有继承。
    C++默认的继承为私有继承,如果是公有继承应改为 class AP_InertialSensor : public AP_AccelCal_Client
    也可以说,AP_AccelCal_Client派生了一个类 AP_InertialSensorAP_AccelCal_Client叫做基类,AP_InertialSensor叫做派生类。

派生类对象存储了基类的数据成员(派生类继承了基类的实现)
派生类对象可以使用基类的方法(派生类继承了基类的接口)
派生类需要自己的构造函数
派生类可以添加额外的数据成员和成员函数
派生类不能直接访问基类的私有成员,只能通过基类的方法进行访问

friend class AP_InertialSensor_Backend;
  1. 定义了类 AP_InertialSensor 的一个友元类 AP_InertialSensor_Backend

友元类的成员函数可以访问原始类的私有成员和保护成员

public:
    AP_InertialSensor();
    /* Do not allow copies */
    AP_InertialSensor(const AP_InertialSensor &other) = delete;
    AP_InertialSensor &operator=(const AP_InertialSensor&) = delete;
  1. 定义默认构造函数 AP_InertialSensor(),通过函数重载,定义另外两个非默认的构造函数。

构造函数是一种特殊的类成员函数,在创建类对象时被调用,构造函数没有类型声明
构造函数的名称与类名相同,但通过函数重载,可以创建多个同名的构造函数
如果只有默认构造函数,可省略。如果定义非默认的构造函数,则必须定义默认构造函数
通常,构造函数用于初始化类对象的成员,初始化应与构造函数的参数列表匹配

  1. =delete 表示对于函数 AP_InertialSensor(const AP_InertialSensor &other),传入参数时该函数被删除。换句话说,敲黑板强调了,不能使用AP_InertialSensor(const AP_InertialSensor &other) 这个函数。同理,后面一句是不允许使用 =AP_InertialSensor 实例进行复制。
public:
    static AP_InertialSensor *get_singleton();
private:
    static AP_InertialSensor *_singleton;
  1. 定义一个 static类(静态类)成员函数 get_singleton(),返回数据类型为AP_InertialSensor类的指针。
  2. 定义一个指针类型的静态类成员 _singleton

静态类成员被所有对象共享,不会随着实例化新的对象而被复制
静态类成员须在类外初始化

静态成员函数属于类,不属于对象,是类域中的全局函数
静态成员函数被类、对象及类的派生类对象所共享
静态成员函数只能调用静态成员,不能调用非静态成员

    void init(uint16_t sample_rate_hz);
  1. 一句很普通的函数声明
    const Vector3f     &get_gyro(uint8_t i) const { return _gyro[i]; }
  1. 声明一个叫做 get_gyro 的函数,返回是对类成员_gyro[i]的引用。引用不会产生新的副本,也就是直接返回每个对象的_gyro[i],不会被复制。
  2. 后面的 const 说明该函数不可修改类成员_gyro[i]的值,前面的 const 说明返回值也是const,即返回值也不可修改。简单说,这是一个“只读”函数。、
  3. 该函数还是一个隐式内联函数,也就是在类内定义,但没用inline显示声明。
    enum Gyro_Calibration_Timing {
        GYRO_CAL_NEVER = 0,
        GYRO_CAL_STARTUP_ONLY = 1
    };
    Gyro_Calibration_Timing gyro_calibration_timing();
  1. 在类里定义了一个枚举类型 Gyro_Calibration_Timing
  2. 定义了一个返回类型为枚举变量的函数。实际上,返回值将是GYRO_CAL_NEVERGYRO_CAL_STARTUP_ONLY,也就是 0 或 1。
    static const struct AP_Param::GroupInfo var_info[];
  1. 这里,AP_Param是一个类,GroupInfo是一个结构体,定义了一个数组 var_info。这里并没有指明数组var_info的长度,因此这是一个动态数组,也就是后面会使用 newdelete来进行动态内存分配。静态数据需要指明数组长度。
  2. 返回类型中,static说明var_info是一个静态成员,该类的所有实例共同拥有该变量,而不是每个对象复制一份。const说明该类的每个对象都不可以修改var_info的值。总结起来,var_info是一个只能初始化一次而不可再被修改的全局变量。
    AuxiliaryBus *get_auxiliary_bus(int16_t backend_id, uint8_t instance);
  1. 该函数返回一个指针变量。问题是什么时候使用指针什么时候使用引用?

参考链接:https://blog.csdn.net/hbtj_1216/article/details/56843014
如果数据对象是数组,则使用指向const的指针
如果数据对象是类对象,则使用const引用,传递类对象参数的标准方式是按引用传递
如果数据对象是较大的结构,则使用const指针或者const引用,以提高程序的效率

    class BatchSampler {
    public:
    	...
    private:
    	...
    };
    BatchSampler batchsampler{*this};
  1. 在原来的类AP_InertialSensor中嵌套一个类BatchSampler
  2. BatchSampler 实例化了一个对象 batchsampler,大括号和圆括号的意思是一样的,都是表示初始化。*this表示传值,this指向BatchSampler的构造函数。

参考链接:https://bbs.csdn.net/topics/394335237
大括号是C++11后的统一初始化对象的一种方式,C++98年代是圆括号和大括号混用的,后来标准委员会的那帮大佬开会讨论后觉得这样不好,就统一都可以用大括号初始化了

private:
    void _start_backends();
	static AP_InertialSensor *_singleton;
    struct {
        float delta_time;
    } _hil {};
  1. private表示成员及方法只能通过类AP_InertialSensor的方法进行赋值与调用。
namespace AP {
    AP_InertialSensor &ins();
}
  1. 自定义了一个命名空间,名叫AP
  2. AP_InertialSensor &ins();不是很清楚,求高见!

参考链接:https://blog.csdn.net/weixin_43796685/article/details/101391950
用户或者C++本身定义了命名空间后,在该命名空间中也是一个独立的作用域,可以和其他作用域中存在相同名称的变量和函数。

— 完 —

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多