day7-多态的理解

多态原理知识点

  • 图解
  • 2.多态原理解析
    • 2.1.当父类中有了虚函数后,内部结构就发生了改变
    • 2.2内部多了一个 vfprt
      - 2.2.1.virtual function pointer 虚函数表指针
      - 2.2.2指向 vftable 虚函数表
      - 2.3父类中结构 vfptr &Animal::speak
    • 2.4 子类中 进行继承 会继承 vfptr vftable
    • 2.5 构造函数中 会将虚函数表指针 指向自己的虚函数表
    • 2.6 如果发生了重写,会替换掉虚函数表中的原有的speak,改为 &Cat::speak
    • 2.7 深入剖析,内部到底如何调用
    • 2.8 ((void(*)()) (*(int*)*(int*)animal))();
    • 猫吃鱼的函数调用(编译器的调用)
    • ((void(*)()) (*((int*)*(int*)animal + 1)))();

day7-多态的理解_第1张图片

代码

#define _CRT_SECURE_NO_WARNINGS
#include
using namespace std;

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

	virtual void eat()
	{
		cout << "动物在吃饭" << endl;
	}

};

class Cat :public Animal
{
public:
	void speak()
	{
		cout << "小猫在说话" << endl;
	}

	virtual void eat()
	{
		cout << "小猫在吃鱼" << endl;
	}
};

//调用doSpeak ,speak函数的地址早就绑定好了,早绑定,静态联编,编译阶段就确定好了地址
//如果想调用猫的speak,不能提前绑定好函数的地址了,所以需要在运行时候再去确定函数地址
//动态联编,写法 doSpeak方法改为虚函数,在父类上声明虚函数,发生了多态
// 多态:父类的引用或者指针 指向 子类对象
void doSpeak(Animal & animal) //Animal & animal = cat
{
	animal.speak();
}
//如果发生了继承的关系,编译器允许进行类型转换

void test01()
{
	Cat cat;
	doSpeak(cat);

}


void test02()
{
	//cout << sizeof(Animal) << endl;
	//父类指针指向子类对象 多态
	Animal * animal = new Cat;

	//animal->speak();
	// *(int*)*(int*)animal 函数地址
	//(void(*)())为函数指针,void (*)( ) ,这是一种变量类型,可用来定义函内数指针变量
	//int(*pFunc3)(int, char) = (int(*)(int, int)) NULL;也是定义函数指针的一种方法
	((void(*)()) (*(int*)*(int*)animal))();

	//  *((int*)*(int*)animal+1)猫吃鱼的地址

	((void(*)()) (*((int*)*(int*)animal + 1)))();
}

int main(){

	//test01();

	test02();

	system("pause");
	return EXIT_SUCCESS;
}

多态重难点

day7-多态的理解_第2张图片
在这里插入图片描述
day7-多态的理解_第3张图片

计算机案例代码

#include 
#include 
#include 

using namespace std;
//开发原则:对扩展进行开放,对修改进行关闭

//利用多态实现计算器
//优点:
//1.组织结构清晰
//2.可读性强
//3.对于前期和后期的扩展以及维护性高
//4.方便扩展而不需要修改源码


//实现计算器抽象类

class AbstractCaculator
{
public:
	//如果父类中有了纯虚函数,子类继承父类,就必须要实现纯虚函数
	//如果父类中有了纯虚函数,这个父类就无法实例化对象了
	//这个类有了纯虚函数,通常称为抽象类
	virtual int getResult() = 0;
	/*virtual int getResult()
	{
		return 0;
	}*/
	int m_Num1;
	int m_Num2;

private:

};

//实现加法类
class AddCaculator :public AbstractCaculator
{
public:
	int getResult()
	{
		return m_Num1 + m_Num2;
	}
};

//实现减法类
class SubCaculator :public AbstractCaculator
{
public:
	int getResult()
	{
		return m_Num1 - m_Num2;
	}
};

//实现乘法类
class MulCaculator :public AbstractCaculator
{
public:
	int getResult()
	{ 
		return m_Num1 * m_Num2;
	}
};

void test01()
{
	//多态使用条件
	//父类指针或者引用指向子类对象

	//加法
	AbstractCaculator* abc = new AddCaculator;
	abc->m_Num1 = 10;
	abc->m_Num2 = 20;

	cout << abc->getResult() << endl;
	delete abc;

	//减法
	abc = new SubCaculator;
	abc->m_Num1 = 10;
	abc->m_Num2 = 20;

	cout << abc->getResult() << endl;
	delete abc;

	//乘法
	abc = new MulCaculator;
	abc->m_Num1 = 10;
	abc->m_Num2 = 20;

	cout << abc->getResult() << endl;
	delete abc;

}

int main()
{
	test01();

	system("pause");
	return 0;
}

虚析构和纯虚析构

注意

  1. 普通析构 是不会调用子类的析构的,所以可能会导致释放不干净
  2. 利用虚析构来解决这个问题
virtual ~Animal()
	{
		cout << "Animal的析构调用" << endl;
	}
  1. 纯虚析构 写法如下
    纯虚析构 ,需要声明 还需要实现 类内声明,类外实现
    virtual ~Animal() = 0;
  2. 如果函数中出现了 纯虚析构函数,那么这个类也算抽象类
    抽象类 不可实例化对象
Animal::~Animal()
{
	纯虚析构函数实现
	cout << "Animal的纯虚析构调用" << endl;
}
  1. 如果出现纯虚析构,类也算抽象类,不能实例化对象
void func()
{
	Animal an;
	Animal * animal = new Animal;
}

代码

#define _CRT_SECURE_NO_WARNINGS
#include
using namespace std;

class Animal
{
public:

	virtual void speak()
	{
		cout << "动物在说话" << endl;
	}

	//普通析构 是不会调用子类的析构的,所以可能会导致释放不干净
	//利用虚析构来解决这个问题
	//virtual ~Animal()
	//{
	//	cout << "Animal的析构调用" << endl;
	//}

	//纯虚析构 写法如下 
	//纯虚析构 ,需要声明 还需要实现 类内声明,类外实现
	virtual ~Animal() = 0;
	//如果函数中出现了 纯虚析构函数,那么这个类也算抽象类
	//抽象类 不可实例化对象

};
Animal::~Animal()
{
	//纯虚析构函数实现
	cout << "Animal的纯虚析构调用" << endl;
}
// 如果出现纯虚析构,类也算抽象类,不能实例化对象
//void func()
//{
//	Animal an;
//	Animal * animal = new Animal;
//}

class Cat:public Animal
{ 
public:
	Cat(const char * name)
	{
		this->m_Name = new char[strlen(name) + 1];
		strcpy(this->m_Name, name);
	}

	virtual void speak()
	{
		cout << "小猫在说话" << endl;
	}
	   
	~Cat()
	{
		cout << "Cat的析构调用" << endl;
		//重要!!!!
		if (this->m_Name !=NULL)
		{
			delete[] this->m_Name;
			this->m_Name = NULL;
		}
	}

	char * m_Name;

};


void test01()
{
	Animal * animal = new Cat("TOM");
	animal->speak();

	delete animal;

}


int main(){

	test01();

	system("pause");
	return EXIT_SUCCESS;
}

你可能感兴趣的:(c++基础学习)