当前位置:   article > 正文

ROS学习笔记5:C++基础知识_ros c++

ros c++

前言:

        作为一名机械专业学生,在没有C++基础的情况下,直接网上的代码资源学习ROS收获不大。虽然老师们并不要求我们会写相关代码,但能看懂代码段的含义是非常必要的,因此在正式开始ROS学习应用前需要对C++有基本概念。

一、C++介绍:

1.面向过程程序设计的缺点:

(1)可读性不佳:在面向过程的程序设计中,函数及其所操作的数据结构没有直观的联系,导致随着程序规模的增加可读性下降。

(2)扩展性差:面向过程程序设计没有“封装”和“隐藏”的概念,要访问某个数据结构中的某个变量可以直接访问,但要修改该变量时需要将所有访问该变量的语句都找出来修改,且难以差错和重用代码。

2.C++的特点:

        C++是C语言的继承,既可以进行C语言的过程化程序设计,又可以进行以抽象数据类型为特点的基于对象的程序设计,还可以进行以继承和多态为特点的面向对象的程序设计。

二、类和对象:

1.介绍类和对象:

(1)面向对象编程:

        面向对象是相对于面向过程来讲的,面向对象思想是把相关的数据和方法组织为一个整体来看待,从更高的层次来进行系统建模。

        面向对象有三大特性:封装、继承和多态。

        C++中的类是实现面向对象编程的核心要素。

(2)类的介绍:

        类是根据客观事物抽象而成,形成一类事物;然后用类去定义对象,形成这类事物的具体个体;类把属性和方法进行封装,同时对类的属性和方法进行访问控制。

        下面举例圆类说明:

1)代码段:

  1. //要使用C++输入输出工具,要提供这两行代码
  2. #include<iostream> //包含输入输出函数的头文件
  3. using namespace std; //释放std命名空间中的变量名,函数名以及类型名
  4. //声明常量PI=3.14
  5. const double PI=3.14;
  6. class Circle
  7. {
  8. public: //访问权限:公共的权限
  9. //属性
  10. double R;//半径
  11. //方法
  12. //获取圆的周长
  13. double cal_zc()
  14. {
  15. return 2*PI*R;
  16. }
  17. //获取圆的面积
  18. double cal_mj()
  19. {
  20. return PI*R*R;
  21. }
  22. };
  23. int main()
  24. {
  25. //创建对象
  26. Circle c; //声明类的对象
  27. c.R=10; //创建对象
  28. cout<<"半径为:"<<c.R<<endl; //访问公共成员属性半径并显示
  29. cout<<"周长为:"<<c.cal_zc()<<endl; //计算周长和面积并显示
  30. cout<<"面积为:"<<c.cal_mj()<<endl;
  31. return 0;
  32. }

2)结果:

3)解释代码: 

        ①Circle是一个类,其中封装了一些方法:

一个属性:R

两个方法:cal_zc()和cal_mj(),分别计算圆的周长和面积

        ②public规定了类中的内容的访问权限。(访问权限有public,private和protected)

public:公有成员,可以在任何地方访问。

private:私有成员,只能在类内部访问。

protected:保护成员,可以在类内部或子类内部访问。

        ③main函数:

  1. int main()
  2. {
  3. //创建对象
  4. Circle c; //声明类的对象
  5. c.R=10; //创建对象
  6. cout<<"半径为:"<<c.R<<endl; //访问公共成员属性半径并显示
  7. cout<<"周长为:"<<c.cal_zc()<<endl; //计算周长和面积并显示
  8. cout<<"面积为:"<<c.cal_mj()<<endl;
  9. return 0;
  10. }

        对象是根据类来创建的,声明类的对象就像声明基本类型的变量一样。

        Circle类的公共成员可以直接被对象用''访问。

        c.R访问了公共成员属性半径。

        c.cal_zc和c.cal_mj访问了两个公共成员函数,分别计算了周长和面积。

(3)类包含的四个要素:

  1. classname
  2. {
  3. access specifiers//访问修饰符:public/private/protected
  4. date members/variables;//变量
  5. member fuctions(){}//方法
  6. };//分号结束一个类

1)类名classname

2)访问修饰符access specifiers

public:公有成员,可以在任何地方访问。

private:私有成员,只能在类内部访问。

protected:保护成员,可以在类内部或子类内部访问。

3)属性

4)方法

        成员函数也可以类内声明,类外实现。注意,在类外实现时需要加上Circle::来指定作用域,表示实现的是Circle类中的成员函数。

  1. class Circle
  2. {
  3. public: //访问权限:公共的权限
  4. //属性
  5. double R;//半径
  6. //方法
  7. //获取圆的周长
  8. double cal_zc();
  9. //获取圆的面积
  10. double cal_mj();
  11. };
  12. double Circle::cal_zc()
  13. {
  14. return 2*PI*R;
  15. }
  16. double Circle::cal_mj()
  17. {
  18. return PI*R*R;
  19. }

(4)class与struct的区别:

        class默认权限为私有private

        struct默认权限为公共public

  1. struct A
  2. {
  3. int iNum;
  4. }
  5. class B
  6. {
  7. int iNum;
  8. }
  9. A a;
  10. a.iNum=2;//没有问题,struct默认权限为public
  11. B b;
  12. b.iNum=2;//编译出错,class默认权限为private

2.创建对象:

(1)对象的初始化和清理:

        对象的初始化和清理是两个非常重要的安全问题。一个对象或者变量没有初始化状态,对其使用后果是未知的。使用完一个对象或变量,没有及时清理也会造成一定的安全问题。

        C++利用构造函数和析构函数解决上述问题,这两个函数会被编译器自动调用。

(2)构造函数:

        构造函数主要作用在于创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无需手动调用。

1)构造函数的结构:

  1. class Person
  2. {
  3. public:
  4. //有参构造函数
  5. Person(string name, int age)
  6. {
  7. this->name=name;
  8. this->age=age;
  9. }
  10. //this是一个指向当前类的指针
  11. //拷贝构造函数
  12. Person(const Person& p)
  13. {
  14. this->name=p.name;
  15. this->age=p.age;
  16. }
  17. //拷贝构造中传入的参数是以引用的方式传入,可节省空间
  18. //const是为了确保不改变传入的参数p
  19. public:
  20. string name;
  21. int age;
  22. };

        该Person类中有两个属性name和age,利用函数重载机制编写了有参构造和拷贝构造两种构造函数,编译器会根据调用时参数的不同,自动选择正确的构造函数。在不提供构造函数时,编译器会自动提供一个默认的无参构造函数。

2)构造函数的调用方法:

  1. #include<iostream>
  2. #include<string>
  3. using namespace std;
  4. class Person
  5. {
  6. public:
  7. //有参构造函数
  8. Person(string name, int age)
  9. {
  10. this->name = name;
  11. this->age = age;
  12. }
  13. //拷贝构造函数
  14. Person(const Person& p)
  15. {
  16. this->name = p.name;
  17. this->age = p.age;
  18. }
  19. public:
  20. string name;
  21. int age;
  22. };
  23. void test01()
  24. {
  25. Person p1("Tom",10);//括号法
  26. Person p2 = Person("John",20);//显式构造法
  27. Person p3 = { "Harry",30 };//隐式构造法
  28. Person p4(p2);//拷贝构造
  29. cout << p1.name << " " << p1.age << endl;
  30. cout << p2.name << " " << p2.age << endl;
  31. cout << p3.name << " " << p3.age << endl;
  32. cout << p4.name << " " << p4.age << endl;
  33. }
  34. int main()
  35. {
  36. test01();
  37. return 0;
  38. }

        有参构造函数有三个调用方法:括号法,显式法,隐式法。

        拷贝构造则是在创建对象p4的时候直接传入一个已有的Person对象p2,利用p2的属性初始化p4。

(3)析构函数:

        析构函数主要作用在于对象销毁前系统自动调用,执行一些清理工作。析构函数在对象消亡时自动调用。析构函数名与类名相同,前面加~,没有参数和返回值。

  1. #include<iostream>
  2. using namespace std;
  3. class Person
  4. {
  5. public:
  6. //有参构造函数
  7. Person(string name, int age)
  8. {
  9. this->name=name;
  10. this->age=age;
  11. cout<<"构造函数调用"<<endl;
  12. }
  13. //析构函数
  14. ~Person()
  15. {
  16. cout<<"析构函数调用"<<endl;
  17. }
  18. public:
  19. string name;
  20. int age;
  21. };
  22. void test02()
  23. {
  24. Person p1("James",30);
  25. cout<<p1.name<<" "<<p1.age<<endl;
  26. }
  27. int main()
  28. {
  29. test02();
  30. cout<<"1111"<<endl;
  31. return 0;
  32. }

         运行结果显示了一个对象从创建到消亡的过程。在“析构函数调用”后打印输出“1111”,说明在执行完函数test02()时析构函数立即被调用,代表在函数中创建的对象被销毁。

3.静态成员:

(1)定义:

        在成员变量和成员函数前加上关键字static称为静态成员。静态成员分为静态成员变量静态成员函数

1)静态成员变量:

        所有对象共享同一份数据;在编译阶段分配内存;类内声明,类外初始化。

2)静态成员函数:

        所有对象共享同一个函数;静态成员函数只能访问静态成员变量。

  1. class Runoob
  2. {
  3. public:
  4. static int runoob_age;//静态变量
  5. int runoob_users;//实例变量
  6. public:
  7. func
  8. {
  9. int runoob_local;//局部变量
  10. };
  11. };

(2)静态成员访问:

        访问方式有两种:对象.或者类名::

  1. #include<iostream>
  2. using namespace std;
  3. class Person
  4. {
  5. public:
  6. static int count;//静态成员变量
  7. string name;
  8. };
  9. int Person::count=10;//类外初始化
  10. void test01()
  11. {
  12. Person p1;
  13. p1.name="Tom";
  14. cout<<"p1的名字:"<<p1.name<<", count:"<<p1.count<<endl;
  15. cout<<"p1的名字:"<<p1.name<<", count:"<<Person::count<<endl;
  16. }
  17. int main()
  18. {
  19. test01();
  20. return 0;
  21. }

        count是Person类中的一个静态成员变量,可以用p1.count和Person::count两种方式来访问。而name是Person类中的一个普通成员变量,只能用p1.name的方式访问。

运行结果如下:

(3)示例:创建了两个对象,都对count属性进行了改变

  1. #include<iostream>
  2. using namespace std;
  3. class Person
  4. {
  5. public:
  6. static int count;//静态成员变量
  7. string name;
  8. };
  9. int Person::count=10;//类外初始化
  10. void test01()
  11. {
  12. Person p1;
  13. p1.count=0;
  14. cout<<"count:"<<Person::count<<endl;
  15. Person p2;
  16. p2.count=10;
  17. cout<<"count:"<<p1.count<<endl;
  18. }
  19. int main()
  20. {
  21. test01();
  22. return 0;
  23. }

运行结果如下:

        运行结果说明Person类的所有对象共享同一个变量count。

4.访问权限:

(1)数据封装:

        数据封装是面向对象编程的一个重要特点,它防止函数直接访问类的内部成员。类成员的访问限制是通过在类主体内部对各个区域标记public、private、protected来指定的。public、private、protected称为访问修饰符。

        一个类可以有多个访问修饰符标记区域,类默认的访问修饰符是ptivate。

(2)访问修饰符:

1)public:公有成员,可以在任何地方访问。

2)private:私有成员,只能在类中或者友元函数中访问。

3)protected:保护成员,可以在类中的函数、子类函数及友元函数中访问。

分析示例:

  1. #include<iostream>
  2. using namespace std;
  3. class Person
  4. {
  5. //姓名,公共权限
  6. public:
  7. string m_Name;
  8. //汽车,保护权限
  9. protected:
  10. string m_Car;
  11. //银行卡密码,保护权限
  12. private:
  13. int m_Password;
  14. public:
  15. void func()
  16. {
  17. m_Name="张三";
  18. m_Car="拖拉机";
  19. m_Password=123456;
  20. cout<<m_Name<<endl;
  21. cout<<m_Car<<endl;
  22. cout<<m_Password<<endl;
  23. }
  24. };
  25. void test01()
  26. {
  27. Person p;
  28. p.func();
  29. cout<<p.m_Name<<endl;
  30. //cout<<p.m_Car<<endl;错误
  31. //cout<<p.m_Password<<endl;错误
  32. }
  33. int main()
  34. {
  35. test01();
  36. return 0;
  37. }

输出结果如下:

         

        在这个例子中可以看出,func()作为成员函数可以访问私有成员变量和保护成员变量,然而在类外函数test01()中就不能访问m_Car和m_Password。

(3)友元:

        类的友元函数是定义在类外部,但有权访问类的所有私有成员和保护成员。尽管友元函数的原型有在类的定义中出现过,但是友元函数并不是成员函数。

        友元可以是一个函数(友元函数),也可以是一个类(友元类),在这种情况下,整个类及其所有成员都是友元。

示例:

  1. #include<iostream>
  2. using namespace std;
  3. class Box
  4. {
  5. double width;
  6. public:
  7. friend void printWidth(Box box);
  8. void setWidth(double wid);
  9. };
  10. //成员函数定义
  11. void Box::setWidth(double wid)
  12. {
  13. width=wid;
  14. }
  15. //请注意:printWidth()不是任何类的成员函数
  16. void printWidth(Box box)
  17. {
  18. /*因为printWidth()是Box的友元,它可以直接访问该类的任何成员*/
  19. cout<<"Width of box:"<<box.width<<endl;
  20. }
  21. //程序的主函数
  22. int main()
  23. {
  24. Box box;
  25. //使用成员函数设置宽度
  26. box.setWidth(10.0);
  27. //使用友元函数输出宽度
  28. printWidth(box);
  29. return 0;
  30. }

输出结果:

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/401120
推荐阅读
相关标签
  

闽ICP备14008679号