学习C++ 笔记 5

Chapter6 多态

1.0 为何要有多态

  • 重定义函数:发生在子类和父类之间
  • 当子类重写父类的成员函数,如果父类中这个函数不是虚函数,是函数的 重定义
  • 如果子类重写父类的成员函数,如果父类中的这个函数是 虚函数。这是函数 的 重写
  • 多态发生必须要有继承,要有子类重写父类的虚函数,以及父类指针(或者引用)指向子类对象。
#include "pch.h"
#include <iostream>
using namespace std;

class Parent
{
public:
	Parent(int a)
	{
		this->a = a;
	}
	virtual void print() //这个virtual是保证给一个成员函数定义为 虚函数,当子类去重写虚函数时,父类指针指向这个函数时,
		//会调用子类的函数。
	{
		cout << "Parent::print():a= " << a << endl;
	}
private:
	int a;
};

class Child :public Parent
{
public:
	Child(int a, int b) :Parent(a)
	{
		this->b = b;
	}
	virtual void print()//重定义父类函数,这里加virtual是为了可读性,将 重定义变为 重写 父类的 虚函数
	{
		cout << "Child::print():b= " << b << endl;
	}
private:
	int b;
};

class Child2 :public Parent
{
public:
	Child2(int a):Parent(a)
	{

	}
	virtual void print()
	{
		cout << "This is a Child 2" << endl;
	}
private:

};


void myPrint(Parent *p)//让父类指针指向子类的对象的时候,就会调用 子类的 重写函数
{
	p->print();//在此时 print函数 发生了 多态现象
}

int main()
{
	Child c(10,20);
	c.print();//20

	Parent p(100);
	p.print();//100

	myPrint(&p);//调用的父类print 100
	myPrint(&c);//10 ,调用的是父类的,编译器会不管传递进来的是 父类还是子类
	//Parent * p =&c,

	Child2 c2(200);
	myPrint(&c2);
}
}

1.1 动态联编和静态联编

  1. 联编是指一个程序模块、代码之间相互关联的过程。
  2. 静态联编(static bingding),是程序的匹配、连接在编译阶段实现,也称为早期匹配。重载函数 使用 静态联编
  3. 动态联编是指程序联编推迟到运行时进行,所以又称为 晚期联编。 swtichif 是动态联编的例子。

1.2 虚析构函数

  • 构造函数 不能虚函数。建立一个派生类对象时,必须从类层次的根开始,沿着继承路径逐个调用基类的构造函数。
  • 析构函数可以是虚的。虚析构函数用于指引 delete运算符正确析构动态对象。
// 虚析构函数.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include "pch.h"
#include <iostream>
#include <cstring>
using namespace std;

class A
{
public:
	A()
	{
		cout << "A()....." << endl;
		this->p = new char[64];
		strcpy_s(p,20,"A string");
	}
	virtual ~A()
	{
		cout << "~A()....." << endl;
		if (p != NULL)
		{
			delete[] p;
			p = NULL;
		}
	}
	virtual void print()
	{
		cout << "A :" << p << endl;
	}
private:
	char *p;
};

class B :public A
{
public:
	B()
	{
		cout << "B()...." << endl;
		this->p = new char[64];
		strcpy_s(p, 20, "B string");
	}

	virtual ~B()
	{
		cout << "~B()....." << endl;
		if (p != NULL)
		{
			delete[] p;
			p = NULL;
		}
	}
	virtual void print()
	{
		cout << "B :" << p << endl;
	}
private:
	char *p;
};

class C :public B
{
public:
	C()
	{
		cout << "C()...." << endl;
		this->p = new char[64];
		strcpy_s(p, 20, "C string");
	}
	virtual ~C()
	{
		cout << "~C()....." << endl;
		if (p != NULL)
		{
			delete[] p;
			p = NULL;
		}
	}
	virtual void print()//多态重写
	{
		cout << "C :" << p << endl;
	}
private:
	char *p;
};

void func(A *p)
{
	p->print();
	delete p;//这里会将p只看作父类指针来释放,而不是释放3次。
	//如果不加虚析构,只会析构父函数一次,加了之后,会优先调用 C的析构函数,来依次析构。
}



int main()
{

	C *cp = new C;
	cp->print();
	delete cp;


	cout << "------------------" << endl;

	C *cp1 = new C;
	func(cp1);//使用多态
 
}

1.3 重载,重写和重定义

重载:

  • 在同一个类中
  • 函数名字相同
  • 参数不同
  • virtual关键字可有可无

重写(覆盖)是指派生类函数覆盖基类函数,特征是:

  • 不同的范围,分别位于基类和派生类中
  • 函数名字相同
  • 参数 相同
  • virtual关键字 必须有

重定义(隐藏) 是指派生类函数 屏蔽了 基类函数,特征是:

  • 如果派生类的函数和基类的函数同名,但是参数不同,此时,不管有无virtual,基类的函数被 隐藏
  • 如果派生类的函数和基类的函数同名,并且参数 相同,但是基类函数 没有 virtual,此时,基类函数被 隐藏

1.4 多态的原理

  • 当类中声明 虚函数 时,编译器会在类中生成一个 虚函数表
  • 虚函数表时一个存储 类成员函数指针 的数据结构
  • 虚函数表时由编译器自动生成与维护的
  • virtual成员函数 会被编译器放入 虚函数表
  • 存在虚函数时,每个对象都有一个指向虚函数的指针( vptr指针 )
#include "pch.h"
#include <iostream>
using namespace std;
class Parent
{
public:
	virtual void func(int a, int b)
	{
		cout << "Parent:func(int a, int b)..." << endl;
	}

	void func(int a, int b, int c)
	{
		cout << "Parent:func(int a, int b, int c)..." << endl;
	}
private:
	int a;
};
class Child :public Parent
{
public:
	void func(int a, int b)
	{
		cout << "Child:func(int a, int b)..." << endl;
	}
	void func(int a, int b, int c)
	{
		cout << "Child:func(int a, int b, int c)..." << endl;
	}
private:
	int b;
};
int main()
{
	Parent *p = new Child;//父类指针指向了 子类对象
	p->func(10, 20);//"Child:func(int a, int b)...",此时发生了多态,调用了Child,动态联编
	p->func(10, 20, 30);//Parent:func(int a, int b, int c)...,此时只有重载,没有多态,静态联编
	
	Parent p1;
	Child c1;
	cout << "szieof Parent " << sizeof(p1) << endl;//此表中由 vptr指针,占用了4个字节,一共8字节
	cout << "szieof Child " << sizeof(c1) << endl;//12字节
}

1.5 vptr指针在构造父类的时候是分步初始化

  • 对象在创建时,由编译器对VPTR指针进行初始化
  • 只有当对象的构造完全结束后VPTR的指向才最终确定
  • 父类对象的VPTR指向父类虚函数表
  • 子类对象的VPTR指向子类的虚函数表
#include "pch.h"
#include <iostream>
using namespace std;

class Parent
{
public:
	Parent(int a)
	{
		cout << "Parent(int a)....." << endl;
		this->a = a;

		print();//这个print是在 Child的 vptr指针尚未建立时的输出,采用的是 Parent的。
	}
	virtual void print()
	{
		cout << "Parent::print() " << a << endl;
	}

private:
	int a;
};


class Child :public Parent
{
public:
	Child(int a, int b) :Parent(a)
	{
		print();//在执行完父类的构造函数以后,vptr指针就建立了,此时执行的是 子类的print
		cout << "Child(int a, int b)....." << endl;
		this->b = b;
	}
	//重写父类的虚函数
	virtual void print()
	{
		cout << "Child::print() " << b << endl;
	}
private:
	int b;
};



int main()
{
	Parent *p = new Child(10, 20);
	p->print();
	delete p;


}


Parent(int a).....
Parent::print() 10
Child::print() -842150451
Child(int a, int b).....
Child::print() 20

1.6 父类指针和子类指针的步长

  • 在父类中,int占据4个字节,VPTP占据4个字节。
#include "pch.h"
#include <iostream>
using namespace std;

class Parent
{
public:
	Parent(int a)
	{
		this->a = a;
	}
	virtual void print()
	{
		cout << "Parent::print()  " << endl;
	}
	int a;
private:
};

class Child :public Parent
{
public:
	Child(int a) :Parent(a)
	{

	}
	virtual void print()
	{
		cout << "Child::print()  " << a << endl;
	}
private:
	int b;//这里添加以后,子类的内存比父类大,12>8,指针++会出错
};


int main()
{
	Parent p1(10);
	Child c1(10);
	cout << "sizeof Child" << sizeof(c1) << endl;//8个字节,VPTR这里未初始化,不存在
	cout << "sizeof Parent" << sizeof(p1) << endl;//8个字节,a占了4个,VPTR指针占了4个

	Child array[] = { Child(0),Child(1),Child(2) };
	//这个不是匿名对象,   array[0],array[1],array[2]

	Child *cp = &array[0];
	Parent *pp = &array[0];

	cout << "------------" << endl;
	cp->print();//Child
	pp->print();//Child 发生多态

	cout << "------------" << endl;
	cp++;//+12个
	pp++;//+8个
	cp->print();//Child
	pp->print();//Child 发生多态


	cout << "------------" << endl;

	int i = 0;
	for (i = 0, pp = &array[0]; i < 3; i++,pp++)
	{
		pp->print();
	}
}

1.7 纯虚函数和抽象类

纯虚函数是一个在 基类 中说明的 虚函数,在基类中没有 定义,要求任何派生类都定义自己的版本。
纯虚函数为多个派生类提供一个公共界面(接口的封装和设计,软件的模块功能划分)

  • 纯虚函数的语法:
    virutual 类型 函数名 (参数表) =0;
    一个具有纯虚函数的基类称为 抽象类

  • 含有纯虚函数的类,称为抽象基类,不可实例化。即不能创建对象,存在的意义就是 被继承,提供族类的公共接口。

  • 纯虚函数只有 声明,没有实现,被“初始化”为0

  • 如果一个类中声明了纯虚函数,而在派生类中没有对该函数的定义,在该虚函数在派生类中仍然为 纯虚函数,派生类仍然为纯虚基类。

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
应用背景为变电站电力巡检,基于YOLO v4算法模型对常见电力巡检目标进行检测,并充分利用Ascend310提供的DVPP等硬件支持能力来完成流媒体的传输、处理等任务,并对系统性能出一定的优化。.zip深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值