当前位置:网站首页>多态的所有特征

多态的所有特征

2022-06-11 21:36:00 爱学代码的学生

1. 什么是多态

同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果,这就是多态性。

简单的说:就是用基类的引用或者指针指向子类的对象

2. 多态的基本语法

基类的指针或者引用执行子类的对象

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

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

class Dog :public Animal
{
public:
	virtual void speak()
	{
		cout << "小狗在说话" << endl;
	}
};

//父类的指针或者引用来执行子类的对象
void dospeak(Animal& animal)
{
	animal.speak();
}

void test()
{
	Cat cat;
	dospeak(cat);

	Dog dog;
	dospeak(dog);
}

int main()
{
	test();
	return 0;
}

3. 多态的底层原理

多态的实现原理是:

1.有继承关系

2.子类要重写父类中的虚函数

什么是虚函数呢?

virtual关键字修饰过的函数称为虚函数

那么在底层,类中拥有被virtual修饰过的函数会产生什么呢?

我们发现类中会产生一个vfptr的指针和一个名为vftable的作用域,这个指针指向这个作用域,而在这个作用域中存在着被virtual修饰的函数的地址

那么子类为什么要重写父类中的虚函数呢?

 我们发现,如果没有重写父类中的虚函数,那么在子类将继承父类中的vftable,那么在调用speak函数时,永远调用的是父类中实现的函数

4. 纯虚函数和抽象类

什么是纯虚函数?

在多态中,我们会发现基类实现的代码基本上是用不到的,那么我们就可以将其设置成纯虚函数

纯虚函数的语法:virtual 返回值 函数名()= 0

class Base
{
public:
	//纯虚函数
	virtual void func() = 0;
};

什么是抽象类?

当一个类中存在了纯虚函数,那么这个类就被称做抽象类

抽象类有什么特点呢?

1. 抽象类无法进行实例化

2. 如果抽象类的子类没有重写纯虚函数,那么该子类也无法进行实例化

5. 纯虚析构和虚析构函数

这里我们先看一段代码:

class Animal
{
public:
	Animal()
	{
		cout << "调用Animal的构造函数" << endl;
	}
	virtual void speak() = 0;

	~Animal()
	{
		cout << "调用Animal 的析构函数" << endl;
	}
};
{
	cout << "调用Animal的析构函数" << endl;	
}
class Cat :public Animal
{
public:
	Cat(string name)
	{
		cout << "调用Cat的构造函数" << endl;
		_name = new string(name);
	}
	virtual void speak()
	{
		cout << *_name<<"猫会说话" << endl;
	}
	string* _name;
	~Cat()
	{
		cout << "调用Cat的析构函数" << endl;
		if (_name != NULL)
		{
			delete _name;
		}
	}
};
void test()
{
	Animal* c = new Cat("Tom");
	c->speak();
	delete c;
}
int main()
{
	test();
	return 0;
}

我们发现当删除c对象时,没有调用子类中的析构函数,而子类中又申请了堆上的空间,那么这样就会造成内存泄漏

那么我们如何保证调用子类中的析构函数呢?

这里我们就需要在父类的析构函数前面加上virtual来修饰

class Animal
{
public:
	//纯虚函数
	Animal()
	{
		cout << "调用Animal的构造函数" << endl;
	}
	virtual void speak() = 0;

	//虚析构和纯虚析构都需要代码的实现
    virtual	~Animal()
	{
		cout << "调用Animal的析构函数" << endl;
	}
};
class Cat :public Animal
{
public:
	Cat(string name)
	{
		cout << "调用Cat的构造函数" << endl;
		_name = new string(name);
	}
	virtual void speak()
	{
		cout << *_name<<"猫会说话" << endl;
	}
	string* _name;
	~Cat()
	{
		cout << "调用Cat的析构函数" << endl;
		if (_name != NULL)
		{
			delete _name;
		}
	}
};
void test()
{
	Animal* c = new Cat("Tom");
	c->speak();
	delete c;
}
int main()
{
	test();
	return 0;
}

 上面我们使用的是虚析构函数来帮助我们解决内存泄漏的问题,这里我们也可以使用纯析构函数来帮助我们

#include"多态.h"

class Animal
{
public:
	//纯虚函数
	Animal()
	{
		cout << "调用Animal的构造函数" << endl;
	}
	virtual void speak() = 0;
	virtual ~Animal() = 0;
};
class Cat :public Animal
{
public:
	Cat(string name)
	{
		cout << "调用Cat的构造函数" << endl;
		_name = new string(name);
	}
	virtual void speak()
	{
		cout << *_name<<"猫会说话" << endl;
	}
	string* _name;
	~Cat()
	{
		cout << "调用Cat的析构函数" << endl;
		if (_name != NULL)
		{
			delete _name;
		}
	}
};
void test()
{
	Animal* c = new Cat("Tom");
	c->speak();
	delete c;
}
int main()
{
	test();
	return 0;
}

 当我们这样去写的时候,我们会发现编译器会报链接的错误

 在使用虚析构来解决问题的时候,我们发现编译器也会调用父类中的析构函数,如果函数中没有进行代码实现,那么就会报错,所以无论是虚析构还是纯虚析构,我们都需要对其进行代码的实现

Animal::~Animal()
{
	cout << "调用Animal的析构函数" << endl;	
}

当在类外实现了纯虚析构的实现,编译器就不再会报错

总结:

纯虚析构函数和虚析构函数的共性:

1.可以解决父类指针释放子类对象不干净的问题
2.都需要具体的代码实现

纯虚析构函数和虚析构函数的不同:

1.如果一个类中存在纯虚析构,这个类处于抽象类,不能进行实例化
2.如果是虚析构,仍可以进行实例化

注:
如果子类中没有堆区的数据,可以不用写纯虚析构或者虚析构

原网站

版权声明
本文为[爱学代码的学生]所创,转载请带上原文链接,感谢
https://blog.csdn.net/rinki123456/article/details/125231794