嘉明的C++学习(3)之继承与多态

嘉明的C++学习之继承与多态

在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述
对应关系表
在这里插入图片描述
在基类私有数据和成员中,派生类无论是怎么继承都不可以访问基类的成员。

如果是私有继承,本来在基类中public属性的成员变量在派生类中都以private属性出现,protected也同样。
在这里插入图片描述
上面是共有派生
这里的int b1是基类的私有数据,所以派生类不可以访问。
int b2是保护数据,因此派生类访问时要以保护的形式访问。
在这里插入图片描述以私有的形式派生,访问一切成员数据都要以私有的形式访问。且如果在派生类中再进行派生,其派生会终止,因为私有类型的数据派生类不可进行访问。

在这里插入图片描述保护类型的派生,访问基类数据时,全部以那保护的形式进行访问。

在这里插入图片描述

#include<iostream>
#include<string>
using namespace std;

class Student{
public:
	Student(int n,string na ,float s):num(n),name(na),score(s){}
	void display(){
		cout<<"num:" << num <<endl
			<<"name:"<< name<<endl
			<<"score:"<<score<<endl;
	}
protected:
	int num;
	string name;
	float score;
};
class Student1:protected Student
{
public:
Student1(int n,string na,float s,int a,string ad)://总参数列表,用冒号隔开
Student(n,na,s)//基类构造函数的参数列表
{
	age = a;
	add = ad;
}
void display1()
{
	display();
	cout<<"age:"<<age<<endl
		<<"addr:"<<add<<endl;
}
void access_base(){
	cout<<"num="<<num<<endl;
}
private:
	int age;
	string add;//新增地址和年龄
};
int main(){
	Student1 stu(2021,"xiaoli",100,18,"NanJing");
	stu.display1();
	stu.access_base();
	return 0;
}

在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述
析构函数与构造函数执行顺序相反,所以最后先执行派生类的析构函数再执行基类的析构函数。

在这里插入图片描述

多重继承

在这里插入图片描述

一个派生类从两个或多个基类派生而来。
在这里插入图片描述
例如沙发床就是一个多重继承的例子,他继承了床和沙发的特点。

在这里插入图片描述
在这里插入图片描述
基类与基类之间用逗号隔开,派生类与基类用冒号隔开。

#include<iostream>
using namespace std;
class B1//第一个基类
{
public:
	int b1;
	B1(int v1):b1(v1){;}
};
class B2//第二个基类
{
public:
	int b2;
	B2(int v2):b2(v2){}
};
class D:public B1,public B2 //多重继承,具有B1与B2的特性.
{
public:int d;
	   D(int v1,int v2,int v3):B1(v1),B2(v2),d(v3){}//构造函数的定义
	   void disp()
	   {
		   cout<<"b1 = "<<b1<<",b2 = "<<b2;
		   cout<<",d = "<<d<<endl;
	   }
};
int main(){
	D demo(10,20,30);
		demo.disp();
	return 0;
}

在这里插入图片描述当基类B1,B2有一个同名成员时,会产生二义性。
在这里插入图片描述这时候就会有一问题,当两个基类的某一个成员同名时,派生类访问的是B1的成员还是B2的成员呢?
这就叫做同成员名二义性

在这里插入图片描述D1、D2当从D1继承B的成员,又从D2继承B的成员时,也会产生二义性
在这里插入图片描述
那么要如何解决这个二义性带来的问题呢?
在这里插入图片描述第一种:带域名直接访问

第二种:使用虚基类。

在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述
构造函数参数声明需要注意,要声明基类的同时也要声明基类的基类的参数

这时A就为D的虚基类,B1、B2为D的直接基类,而不是D的虚基类

在这里插入图片描述在这里插入图片描述这里的disp1有两个,来自B1、B2,所以通过使用域名的方法解决这个二义性。(同名成员带来的二义性)

这里的成员a属于基类的基类A,而B1、B2都继承了A中的a,D又属于B1、B2的派生类,所以这样继承下来就会就会产生二义性,这时候就通过虚函数来解决这个问题(同一个基类被多次继承产生的二义性)

多重继承

在这里插入图片描述
多态就执行同一个指令时表现出不同的动作,例如,狗和猫都属于动物类,它们都执行叫这个动作时,
狗是汪汪汪叫

猫是喵喵喵叫
这就是所谓的多态的理解

在这里插入图片描述
C++中的多态就是一种函数的多种形态

编译时多态又称为静态联编,通过重载机制来实现(例如函数重载等等机制)。

运行时多态称为动态联编,通过虚函数和继承来实现。

那么什么是虚函数呢?

在这里插入图片描述在这里插入图片描述
理解
(1)该用基类的地方可以用派生类代替,(参数、对象赋值等等)
(2)基类的指针可以指向派生类

这是没有虚函数的代码,但是固有的性质
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
bp是基类指针

最后的结果都是调用基类函数输出call base class,不过数值为11、12、13而已

而我们想输出的结果是带call deliver class 的

说明都是受限于基类,而不能调用派生类中的class deliver class

这就是不加虚函数的静态联编,不会出现所谓的动态联编。

在这里插入图片描述受限:是因为私有派生,不可访问数据,只有共有派生才能实现。

在这里插入图片描述在这里插入图片描述在这里插入图片描述这里定义的pb=&d,pb->show(),本来是我们的意思是调用派生类的show

但偏偏结果却是调用了基类的show()

这就说明了一个问题,这是静态联编

因此想要调用派生类的函数,必须要使用虚函数定义与派生类同名的函数(并不是虚基类),使基类的指针指向派生类时,并且可以使用它

在这里插入图片描述在这里插入图片描述在这里插入图片描述虽然上面的语句都一致,但是所执行的功能却不同,这就是虚函数的作用,以及C++多态的体现。

注:最后一行是引用
形式 &x = y

指针传地址一般是 x =&y

#include<iostream>
using namespace std;
class Base
{
public:virtual void show(){
		   cout<<"Base class\n";}

};
class Derived:public Base
{
public:
	void show()
	{
		cout<<"Derived class\n";
	}
};
class Derived2:public Base
{
public: void show(){
			cout<<"Derived2 class\n";
		}
};
int main(){
	Base bobj,*p;
	Derived dobj1;
	Derived2 dobj2;
	p = &bobj;
	p->show();
	p = &dobj1;
	p->show();
	p = &dobj2;
	p->show();
	Base &bref = dobj2;
	bref.show();
	return 0;
}

在这里插入图片描述虚函数的定义有点相似与虚基类解决二义性的问题
但是不能搞混。

在这里插入图片描述在这里插入图片描述
重要的点:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述
在这里插入图片描述

纯虚函数与抽象类

在这里插入图片描述
例如上面的代码,只定义了一个图像类,而派生出圆形、三角形、正方形等等类,这个图像类就是抽象的东西,没什么具体意义。这时候就可以把它的某个函数定义为纯虚函数(无任何功能,不能调用),为派生类保留一个公共接口,方便多态运行。

在这里插入图片描述在这里插入图片描述只要有一个纯虚函数就是抽象类

其作用是提供一个公共的接口,提高派生类中继承中的层次性,纯虚函数功能的实现具体有派生类来完成

在这里插入图片描述不能建立抽象类对象,但是可以建立指针来完成多态。

重要:
在这里插入图片描述
在这里插入图片描述重要:
在这里插入图片描述代码:
在这里插入图片描述在这里插入图片描述在这里插入图片描述这里是S[0] = new Triangle(1,2)相当于把Triangle 的对象地址赋值给S[0],因为对象的定义有两种
1、类名 对象名
2、new 类名

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述new时,创建对象时自动调用构造
delete时,自动调用析构

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值