面向对象中类是程序基本单元,分为类内和类外数据共享和保护

1、类的静态成员

1.1、类静态成员概述
有时我们可能希望有某一个或几个数据成员为同一个类的所有对象共有,也就是实现数据共享

静态成员提供一种同类对象对数据的共享机制

静态成员分为:
静态数据成员
静态成员函数

静态数据成员是类的属性,这个属性不属于类的任何对象,但所有的对象都可以访问和使用它


如果将类的一个成员定义成静态型的,则该类的所有对象的该成员共用同一存储空间。

1.2、静态数据成员的初始化

1.3、例子
每定义一个对象 执行一次构造函数;count++一次;

#include<iostream>
using namespace std;

class Student
{
public:
    Student();
    ~Student(); 
    void output();
    int totalStu();
private:
    int stuNum;
    char name[20];
    char sex[3];
    static int count; //count为私有的,用于统计学生对象的人数 
};

int Student::count=0;

Student::Student()
{
  count++;
  cout<<"请输入第"<<count<<"个学生的姓名:";
  cin>>name;
  cout<<"请输入学号:";
  cin>>stuNum;
  cout<<"请输入性别:";
  cin>>sex;
}
Student::~Student()
{
   cout<<"学生"<<count<<"析构!"<<endl; 
   count--;
}
void Student::output()
{
  cout<<"姓名:"<<name<<endl;
  cout<<"学号:"<<stuNum<<endl;
  cout<<"性别:"<<sex<<endl;
}
int Student::totalStu()
{
    return count;
}
int main()
{   
    Student a1,a2;
    cout<<"当前的学生总人数为:"<<a1.totalStu()<<endl;
    {        
          Student a3;
          cout<<"第三个学生对象生成之后,";
          cout<<"总人数为:"<<a1.totalStu()<<endl;
    }
    cout<<"当前的学生总人数为:"<<a2.totalStu()<<endl; 

    return 0;
}

1.4、LIO-SAM
可以看到在LIO-SAM中定义静态变量时在定义之初即进行了初始化;

并且ang_res_x代表角度分辨率;ringFlag代表雷达是否有线号;这两个变量的都只与使用的激光雷达有关;不随着类所创建的对象不同而改变

static float ang_res_x = 360.0/float(Horizon_SCAN);
static int ringFlag = 0;

2、 类的静态函数成员

2.1、概述
静态成员函数是类的一部分,而不是对象的一部分。如果要在类外调用公用的静态成员函数,要使用类名和域运算符” ::”,其格式为:

类名::静态成员函数名(实参表);

对象名.静态成员函数名(实参表) ;

#include <iostream>
using namespace std;
class Student                    //定义Student类
{
    int num;
    int age;
    float score;
    static float sum;                //静态数据成员
    static int count;              //静态数据成员
  public:
    Student(int n,int a,float s):num(n),age(a),score(s){ }       
    void total( );
    static float average( );      //声明静态成员函数 
};

void Student::total()            //定义非静态成员函数
{
    sum+=score;                   //计算总分
     count++;                      //累统计总人数
}

float  Student::average( )       //定义静态成员函数
{
   return(sum/count);
}

float Student::sum=0;            //对静态数据成员初始化
int Student::count=0;            //对静态数据成员初始化

int main( )
{    
  Student stu[10]={               //定义对象数组并初始化
    Student(10010,18,93),
    Student(10020,19,68),
    Student(10030,19,79),
    };

  int n;
  cout<<"请输入学生个数(1--3):";
  cin>>n;                          //输入需要求前面多少名学生的平均成绩
  for(int i=0;i<n;i++)
  {                  
       stu[i].total( );
  } 
  cout<<"前 "<< n<<" 位学生的平均成绩为 "<<Student::average( )<<endl;  

  return 0;
}

3、类的友元
C++为了进一步提高数据共享,通过友元机制实现类外数据共享

友元不是该类的成员函数,但是可以访问该类的私有成员
• 对于一个类而言,它的友元是一种定义在该类外部的:
普通函数, 或者– 另一个类的成员函数, 或者– 另一个类,
但需要在该类体内进行说明。

3.1、友元函数
3.1.1、非成员函数(普通函数) 作为友元函数
将一个函数声明为一个类的友元函数后,它不但可以通过对象名访问类的公有成员,而且可以通过对象名访问类的私有成员和保护成员

访问对象中的成员必须通过对象名

友元函数近似于普通的函数,它不带有this指针, 因此必须将对象名或对象的引用作为友元函数的参数,这样才能访问到对象的成员。

友元函数可以访问该类中的所有成员(公有的、私有的和保护的) ,而一般函数只能访问类中的公有成员

#include <iostream>
using namespace std;

class A{
    float x, y;
public:
    A(float a, float b){x=a; y=b;}
    float GetX(){return x;}
    float GetY(){return y;} 
    float Sum(){ return x+y; }      //成员函数 
    friend float Sum(A &a);         //友元函数声明 
} ;
float Sum(A &a)     { return a.x + a.y;    }  //友元函数定义 

float SumXY(A &a) //普通函数定义 
{
    return a.GetX()+a.GetY();  
}

int main(){
    A t1(4,5), t2(10,20), t3(100,200);
    cout<<t1.Sum()<<endl; //成员函数的调用,利用对象名调用
    cout<<Sum(t1)<<endl;  //友元函数的调用,直接调用
    cout<<SumXY(t1)<<endl; //调用一般函数
    return 0; 
}

3.2、友元类
当一个类作为另一个类的友元时,就意味着这个类的所有成员函数都是另一个类的友元函数

4、 数据的共享与保护
对于既需要共享、又需要防止改变的数据应该声明为常量

4.1、常对象
常对象中所有数据成员为常变量,必须要有初始值,且均不能被更新

常对象的数据成员是常数据成员,但成员函数如不加const声明,编译系统将其作为非const成
员函数

常对象只能调用其常成员函数,常成员函数是常对象唯一的对外接口

常成员函数可以访问常对象中的数据成员,但不允许修改常对象中数据成员的值。

4.1.1 、常对象函数

#include<iostream>
using namespace std;

class Count{
public:
    int add() const;    //常成员函数的声明,是常对象的对外接口 
    void add1() const  //常成员函数
    {
        cout<<" add1 "<<endl;
    }
    void add2()     // 普通函数 
    {
        cout<<"add2"<<endl; 
    }
};

int Count::add() const //常成员函数的实现 
{ 
  cout<<" add --"<<endl;
  return 0;
}

int main()
{    const Count c1;  //c1是常对象 
    c1.add();   //add()是const,则c1可以调用 
    c1.add1();  //add1()是const,则c1可以调用 
    c1.add2();  //错误,常对象不能调用普通成员函数 
    return 0;
}

4.2.2、常对象成员

4.3、常引用

#include "iostream"
using namespace std;
void Output( const  int &i)
{
    //i++;      //错误,常量引用作为形参,其值不能被改变
    cout<<i<<endl;
}

int main()
{
    int i=12;
    Output(i);
    return 0;
}

4.3.1、A-LOAM
为了防止从雷达接受的点(pi)在输入转变的过程中被改变定义成常引用

//把某点的坐标从lidar坐标系转换到世界坐标系下。
void pointAssociateToMap(PointType const *const pi, PointType *const po)
{
    Eigen::Vector3d point_curr(pi->x, pi->y, pi->z);
    Eigen::Vector3d point_w = q_w_curr * point_curr + t_w_curr;
    po->x = point_w.x();
    po->y = point_w.y();
    po->z = point_w.z();
    po->intensity = pi->intensity;
    //po->intensity = 1.0;
}