c++多态

多态

多态:一个接口,多种实现。

静态多态:编译时 (函数重载,操作符重载和模板)
动态多态:运行时(派生类,虚函数)—类继承

重载:是函数或者方法有相同的名称,但是参数列表不相同,这样的同名不同参数的函数或者方法之间,互相称之为重载函数或者方法。
重写(覆盖):是子类对父类的允许访问的方式的实现过程进行重新编写,返回值和形参不能改变(virtual函数)。
重定义(隐藏):重新定义父类的同名成员函数(非virtual函数)。

重定义

#include<iostream>
using namespace std;

class A
{
	public:
	void print()
	{
		cout<< " A::print()"<<endl;
	}	
};

class B:public A
{
	public:
	void print()
	{
		cout<< " B::print()"<<endl;
	}
};

int main()
{
	A a;
	B b;
	a.print();
	b.print();
	
	A & obj=b; //隐式类型转转 
	obj.print(); //这里输出 “A::print()”
	return 0;
}

不是多态看类型,因此调用的是父类的print()函数。

重写

#include<iostream>
using namespace std;

class A
{
	public:
	virtual void print() 
	{
		cout<< " A::print()"<<endl;
	}	
};

class B:public A
{
	public:
	void print()
	{
		cout<< " B::print()"<<endl;
	}
};

int main()
{
	A a;
	B b;
	a.print();
	b.print();
	
	A & obj=b; //隐式类型转换  这里进行转换时  虚函数表的信息不会发生变化 
	obj.print();  //这里输出 B::print()
	return 0;
//另一种 方法  父类的指针指向子类的对象
//A * pa = new B();  //子类可以转化为父类
//pa->print();      // 这里输出 B::print()

//子类不允许访问父类
//B* pb = new A();  错误的  父类不允许转化为子类
}

动态多态的作用

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

class A
{
	public:
	virtual void print()
	{
		cout<< " A::print()"<<endl;
	}	
};

class B:public A
{
	public:
	void print()
	{
		cout<< " B::print()"<<endl;
	}
};

class C:public A
{
	public:
	void print()
	{
		cout<< " C::print()"<<endl;
	}
};

void print(vector<A*>& arr)
{
	for(auto it :arr)
	{
		it->print();
	}
 } 

int main()
{
// 动态多态的作用 
A* pa1 = new B(); //可以 子类可转化为父类 
 pa1->print();
 A* pa2 = new C();  //子类可转化为父类 
  pa2->print();
  
  
	vector<A*> arr;
	arr.push_back( new B());
	arr.push_back(new C());
	print(arr);
	return 0;
}

virtual关键字不能修饰的函数有哪些?

1、构造函数
2、全局函数
3、静态成员函数
4、友元函数
5、inline函数 在编译时进行展开

在这里插入图片描述

纯虚函数表:

纯虚函数的定义 virtual void test()=0;
带有纯虚函数的类可以称为纯虚类

虚析构函数是为了解决基类的指针指向派生类对象,并用基类的指针删除派生类对象

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

class Car
{
	public:
		 ~Car()
		{
			cout<<"Car destructor" <<endl;
		}
};

class BWM: public Car
{
	
	private:
		char * _name; 
	public:
	BWM(const char *s):_name(nullptr)
	{
		int len = strlen(s);
		_name = new char[len +1];
		strncpy(_name,s,len);
		_name[len] = '\0';
	}
	~BWM()
	{
		cout<< "BWM destructor" <<endl;	
		delete[] _name;
	}	
};

int main()
{
	Car *p = new BWM("bwm770");
	delete p; //输出的是"Car destructor"。   没有输出 " BWM destructor"会造成内存泄漏 
	return 0;
}

如何解决,使用虚析构函数。

#include<iostream>
#include<cstdio>
#include<vector>
#include<string.h>
#include<algorithm>
using namespace std;

class Car
{
	public:
		virtual ~Car() //声明成虚析构
		{
			cout<<"Car destructor" <<endl;
		}
};

class BWM: public Car
{
	
	private:
		char * _name; 
	public:
	BWM(const char *s):_name(nullptr)
	{
		int len = strlen(s);
		_name = new char[len +1];
		strncpy(_name,s,len);
		_name[len] = '\0';
	}
	~BWM()
	{
		cout<< "BWM destructor" <<endl;	
		delete[] _name;
	}	
};

int main()
{
	Car *p = new BWM("bwm770");
	delete p; 
	return 0;
}

为什么会出现此问题?
在没有对基类的析构函数加虚函数时
可以正常释放父类“car destructor”的资源,但是不能释放子类“BWM destructor”的资源。
通常情况下类的析构函数里面都是释放内存资源,而析构函数不被调用的话就会造成内存泄漏。**原因是指针p是Car(父类)类型的指针,释放时只进行Car类的析构函数,**对其加上Virtual后会释放父类和子类的内存 。

抽象基类与虚函数

在设计时,常常希望基类仅仅作为其派生类的一个接口。这就是说,仅想对基类进行向上类型转换,使用它的接口,而不希望用户实际的创建一个基类的对象。同时创建一个纯虚函数允许接口中放置成员原函数,而不一定要提供一段可能对这个函数毫无意义的代码。

做到这点,可以在基类中加入至少一个纯虚函数(pure virtual function),使得基类称为抽象类(abstract class).

1、纯虚函数使用关键字virtual,并在其后面加上=0。如果试图去实例化一个抽象类,编译器则会阻止这种操作。
2、当继承一个抽象类的时候,必须实现所有的纯虚函数,否则由抽象类派生的类也是一个抽象类。
3、Virtual void fun() = 0;告诉编译器在vtable中为函数保留一个位置,但在这个特定位置不放地址。

#include<iostream>
using namespace std;

//抽象制作饮品
class AbstractDrinking{
public:
	//烧水
	virtual void Boil() = 0;
	//冲泡
	virtual void Brew() = 0;
	//倒入杯中
	virtual void PourInCup() = 0;
	//加入辅料
	virtual void PutSomething() = 0;
	//规定流程
	void MakeDrink(){
		Boil();
		Brew();
		PourInCup();
		PutSomething();
	}
};

//制作咖啡
class Coffee : public AbstractDrinking{
public:
	//烧水
	 void Boil(){
		cout << "煮农夫山泉!" << endl;
	}
	//冲泡
	 void Brew(){
		cout << "冲泡咖啡!" << endl;
	}
	//倒入杯中
	 void PourInCup(){
		cout << "将咖啡倒入杯中!" << endl;
	}
	//加入辅料
 void PutSomething(){
		cout << "加入牛奶!" << endl;
	}
};

//制作茶水
class Tea : public AbstractDrinking{
public:
	//烧水
	 void Boil(){
		cout << "煮自来水!" << endl;
	}
	//冲泡
 void Brew(){
		cout << "冲泡茶叶!" << endl;
	}
	//倒入杯中
	 void PourInCup(){
		cout << "将茶水倒入杯中!" << endl;
	}
	//加入辅料
 void PutSomething(){
		cout << "加入食盐!" << endl;
	}
};

//业务函数
void DoBussiness(AbstractDrinking* drink){
	drink->MakeDrink();
	delete drink;
}

void test(){
	DoBussiness(new Coffee);
	cout << "--------------" << endl;
	DoBussiness(new Tea);
}
int main()
{
	test();
	return 0;
}

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值