浅谈C++多态

多态:多态指一种事物有多种状态,如车有奔驰宝马,人有学生老师;

多态分类

静态类型多态:静态类型多态也称作编译期间多态,指在编译期间完成后,就已经确定了调用那一方法,如果存在则调用,如果不存在,则编译错误。

  • 函数重载(普通函数的重载&成员函数的重载)

//普通函数的重载
int add(int left,int right)
{
	return left + right;
}
double add(double left,double right)
{
	return left + right;
}
//成员函数的重载
class Sum
{
	public:
	int sum(int left,int right)
	{
		return left + right;
	}
	double sum(double left,double right)
	{
		return left + right;
	}
};
  • 函数模板的使用
template<class T>
T add(T left,T right)
{
	return left + right;
}

动态类型多态:动态类型多态也称作运行时多态,指在运行期间判断所引用对象的实际类型,调用相对应方法。
首先搞清楚这个对象的类型
静态类型:对象声明时的类型,编译时确定;
动态类型:目前对象真实指向数据的类型,运行时确定;
在这里插入图片描述
(注:上述未delete请读者注意自行delete)
动态多态必须在继承体系下实现,要实现动态多态必须要满足条件:

  1. 在继承体系中基类必须要有虚函数,
  2. 子类必须要重写基类的虚函数
  3. 必须通过基类的指针或者引用来调用这些虚函数
class Base
{
	public:
	virtual void f1()
	{
		cout << "Base::f1()" << endl; 
	}
};
class Derived : public Base
{
	public:
	virtual void f1()
	{
		cout << "Derived::f1()" << endl;
	}
};

int main()
{
	Base b;
	Derived d;

	//指针调用
	Base* ptr1 = &b;
	ptr1->f1();//调用Base的f1();
	ptr1 = &d;
	ptr1->f1();//调用Derived的f1();
	
	//引用调用
	Base& r = b;
	r.f1();//调用Base的f1();
	Base& rr = d;
	rr.f1();//调用Derived的f1();
}

重载,重写(覆盖),重定义(同名隐藏)的区别
在这里插入图片描述
函数重载
此处着重讲一下重定义&重写

  1. 重定义字面意思就是定义了多次,是指在继承体系中函数或者变量的名字相同,原基类中与子类相同名字的函数或者变量就被隐藏,想要用子类访问基类的这些方法就得加上作用域限定符。
class Base
{
	public:
	void f1()
		{cout << "Base::f1()" <<endl;}
	int _b;
};
class Derived : public Base
{
	public:
	void f1()
		{cout << "Derived::f1()" <<endl;}
	int _b;
};
int main()
{
	Derived d;
	//访问子类的成员变量和成员函数
	d.f1();
	d._b = 1;
	//访问基类的成员变量和成员函数
	d.Base::f1();
	d.Base::_b = 2;
	return 0;
}

2.重写字面意思即是重新写一份方法即覆盖,是指在继承体系中基类的虚函数被子类重新书写一份,此子类中不在含有基类此方法。

class Base
{
	public:
	virtual void f1()
		{cout << "Base::f1()" <<endl;}
};
class Derived : public Base
{
	public:
	virtual void f1()
		{cout << "Derived::f1()" <<endl;}
};
void Test(Base& b)
{
	b.f1();
}
int main()
{
	Base b;
	Derived d;
	Test(b);//调用基类f1()
	Test(d);//调用子类f1()
	return 0;
}

注:重定义子类本质上还存在基类的成员函数和成员变量,但是重写子类将不再存在基类的成员函数;
虚函数表
对于存在虚函数的非继承类,编译器一般都会维护一张虚表,对象的前四个字节一般存放的都是指向这张虚表的指针(虚表指针),虚表中存放的是该对象的虚函数地址;
虚表的创建分为两种情况:

  1. 无覆盖(基类的虚函数在子类中没有重写)
class Base
{
	virtual void f1();
	virtual void f2();
};
class Derived : public Base
{
	virtual void f3();
	virtual void f4();
};

在这里插入图片描述

  • 函数按照声明依次存放到虚表中
class Base
{
	virtual void f1();
	virtual void f2();
};
class Derived : public Base
{
	virtual void f1();
	virtual void f2();
	virtual void f3();
	virtual void f4();
};

在这里插入图片描述

  • 先拷贝基类虚函数表
  • 如果子类有重写则替换虚函数表中此函数对应位置的函数地址
  • 将新添加的虚函数加到后面
    总结:通过基类的指针或者引用调用虚函数,要根据运行期间指针实际指向或者引用实际引用的数据来调用对应的虚函数,调用非虚函数时,实际调用的都是基类的函数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值