ROS学习笔记6:C++基础知识(续)

 三、继承与多态:

1.基类与派生类:

(1)继承:

        面对对象程序设计中最重要的一个概念是继承。

        继承允许我们根据一个类去定义另一个类,这使得创建和维护一个应用程序变得更容易。这样做也达到了代码复用功能和提高执行效率的效果。当创建一个类时,不需要重新编写新的数据成员和成员函数,只需指定新建的类继承了一个已有的类的成员即可。这个已有的类称为基类,新建的类称为派生类。

(2)继承的基本语法:

class 子类 :继承方式 父类

2.继承方式:

(1)公有继承(public):

class Base
{
public:
	int m_A;
protected:
	int m_B;
private:
	int m_C;
};

 
class Son1 :public Base
{
public:
	void func()
	{
		m_A;//可访问,为public权限
		m_B;//可访问,为protected权限
		//m_C;//不可访问 
	}
};

void test01()
{
	Son1 s1;
	s1.m_A;
	//s1.m_B;//错误,protected
	//s1.m_C;//错误,父类private 
}

        子类Son1以公共的方式继承了Base类,在其内部可以访问m_A和m_B,不能访问父类中的私有成员m_C。类外的全局函数test01()中创建了Son1的对象s1,但只能访问m_A。

(2)保护继承(protected):

class Base
{
public:
	int m_A;
protected:
	int m_B;
private:
	int m_C;
};

 
class Son2 :protected Base
{
public:
	void func()
	{
		m_A;//可访问,为protected权限
		m_B;//可访问,为protected权限
		//m_C;//不可访问 
	}
};

void test02()
{
	Son2 s2;
	//s2.m_A;//错误,protected
	//s2.m_B;//错误,protected
	//s2.m_C;//错误,父类private 
}

        子类Son2以保护的方式继承了Base类,在其内部可以访问m_A和m_B且它们都是保护成员,不能访问父类中的私有成员m_C。类外的全局函数test01()既不能访问保护成员m_A和m_B,也不能访问m_C。

(3)私有继承(private):

class Base
{
public:
	int m_A;
protected:
	int m_B;
private:
	int m_C;
};

 
class Son3 :private Base
{
public:
	void func()
	{
		m_A;//可访问,为private权限
		m_B;//可访问,为private权限
		//m_C;//不可访问 
	}
};

class GrandSon3 :public Son3
{
public:
	void func()
	{
		//m_A;//不可访问,为private权限
		//m_B;//不可访问,为private权限
		//m_C;//不可访问,为private权限
	}
};

        子类Son3以私有的方式继承了Base类,在其内部可以访问m_A和m_B且它们都是私有成员,不能访问父类中的私有成员m_C。

        子类Son3的子类GrandSon3(姑且叫它孙子类吧)以公共的方式继承了Son3类,但由于Son3类中的成员均为私有权限,因此m_A和m_B以及m_C都不可访问。

        综上,我们可以做出如下总结:

①子类无法访问父类的private成员。

②公有继承方式会保持父类成员的权限等级。

③保护继承方式会将父类的public权限升级为protected权限。

④私有继承方式会将父类的public和protected权限升级为privated权限。

3.继承中的构造与析构的调用原则:

(1)子类对象在创建时会首先调用父类的构造函数。

(2)父类构造函数执行结束后,执行子类的构造函数。

(3)当父类的构造函数有参数时,需要在子类的初始化列表中显式的调用。

(4)析构函数调用的先后顺序与构造函数相反。

#include
using namespace std;

class Base
{
public:
	Base()
	{
		cout<<"Base构造函数"<

运行结果:

ROS学习笔记6:C++基础知识(续)_第1张图片

4.多态:

(1)基本概念:

        多态(即“多种形态”)面向对象的基本特征之一。当类之间存在层次结构,并且类之间是通过继承关联时,就会用到多态,意味着调用成员函数时,会根据调用函数对象的类型来执行不同的函数。

(2)多态的好处:

1)应用程序不必为每一个派生类编写功能调用,只需要对抽象基类进行处理即可,大大提高了程序的可复用性。

2)派生类的功能可以被基类的方法或引用变量所调用,这叫向后兼容,提高可扩展性和可维护性。

(3)示例:

#include
#include
using namespace std;

class Animal
{
public:
	virtual void speak()
	{
		cout<<"动物在说话"<

运行结果:

ROS学习笔记6:C++基础知识(续)_第2张图片

        C++ 中父类的指针或者引用可以指向子类对象,因此Cat对象传入DpSpeak()函数编译器不会报错。

        Animal类中的成员函数speak()前加virtual表示其是虚函数,编译器在编译阶段不能确定函数调用。

        多态使得真正调用的函数地址在运行的时候才能确定,称为动态联编

        多态的使用可用于许多不同的Animal子类,DoSpeak()函数只需写一次即可。

        多态满足条件:①有继承关系;②子类重写父类中的虚函数。

四、模板:

1.模板介绍:

       模板是泛型编程的基础,泛型编程是以一种独立于任何特定类型的方式编写代码。

        我们需要开发一个函数用于不同的数据类型,且不希望重复做类似的工作,比如下面这个例子:

//交换整型数
void swapInt(int& a, int& b)
{
    int temp=a;
    a=b;
    b=temp;
}

//交换浮点型数
void swapDouble(double& a, double& b)
{
    double temp=a;
    a=b;
    b=temp;
}

        模板可以很好地解决这个问题,它可以将数据类型作为参数传递

2.函数模板:

(1)语法:

template

template:声明创建模板

typename:表明其后面的符号是一种数据类型,可以用class代替

T:通用的数据类型(这里的T可以替换为其它大写字母)

(2)示例1:

#include
using namespace std;
 
template

void mySwap(T& a, T& b)
{
    T temp=a;
    a=b;
    b=temp;
}

void test01()
{
    int a=10;
    int b=20;
    mySwap(a,b);
    cout<<"a="<ROS学习笔记6:C++基础知识(续)_第3张图片

        函数模板用字母T来代表一种类型,可以根据实际调用时传入的变量类型自动推导出T所代表的类型。无论传入的变量类型是int,double还是char都能够被自动推导出来。

 (3)示例2:

        调用时也可以显式地指定类型。

#include
using namespace std;
 
template

void mySwap(T& a, T& b)
{
    T temp=a;
    a=b;
    b=temp;
}

void test02()
{
    double c=10.1;
    double d=20.2;
    //mySwap(c,d);
    mySwap(c,d);
    cout<<"c="<mName<<"age:"<mAge<p("孙悟空",1000);
	p.showPerson();
}

void test02()
{
	Personp("猪八戒",999);
	p.showPerson();
}

int main()
{
	test01();
	test02();
	return 0;
}

        类模板不能自动进行类型推导,必须显式指定类型。类模板中的模板参数可以有默认参数。

        类模板中的成员函数也可以类内声明类外实现,但是在类外必须加上模板参数列表。

你可能感兴趣的:(ROS编程技术,c++,学习)