首先需要明确多态性的用途,是为了接口的最大程度复用,以及其定义:
多态性的定义,可以简单地概括为“一个接口,多种方法”,程序在运行时才决定调用的函数,它是面向对象编程领域的核心概念。多态(polymorphism),字面意思多种形状。多态分为静态多态和动态多态。
静态多态是通过重载和模板技术实现,在编译的时候确定。
动态多态通过虚函数和继承关系来实现,执行动态绑定,在运行的时候确定。
定义明确,接下来看看最常见的动态多态的实现思路:对于一组相关的数据类型,抽象出它们之间共同的功能集合,在基类中将共同的功能声明为多个公共虚函数接口,子类通过重写这些虚函数,实现各自对应的功能。在调用时,通过基类的指针来 *** 作这些子类对象,所需执行的虚函数会自动绑定到对应的子类对象上。
上述可以看出,动态多态的实现关键在于虚函数,基类通过virtual关键字声明和实现虚函数,此时基类会拥有一张虚函数表,虚函数表会记录其对应的函数指针。当子类继承基类时,子类也会获得一张虚函数表,不同之处在于,子类如果重写了某个虚函数,其在虚函数表上的函数指针会被替换为子类的虚函数指针。
1.实现代码#include
using namespace std;
// 动物类
class Animal {
public:
//虚函数
virtual void speak() {
cout << "动物在说话" << endl;
}
};
// 猫类
class Cat :public Animal
{
public:
void speak()
{
cout << "小猫在说话" << endl;
}
};
//狗类
class Dog :public Animal {
public:
void speak()
{
cout << "小狗在说话" << endl;
}
};
//执行说话的函数
//地址早绑定 在编译阶段提前确定函数地址
//如果想执行让猫说话,那么这个函数地址就不能提前绑定,需要在运行阶段进行绑定,地址晚绑定
//利用动态多态
void doSpeak(Animal& animal) {
animal.speak();
}
void test01()
{
Animal animal;
doSpeak(animal);
Cat cat;
doSpeak(cat);
Dog dog;
doSpeak(dog);
}
//分别利用普通写法和多态技术实现计算器
//普通写法
class Calculator {
public:
int retResult(string oper)
{
if (oper == "+")
{
return m_num1 + m_num2;
}
else if (oper == "-")
{
return m_num1 - m_num2;
}
else if (oper == "*")
{
return m_num1 * m_num2;
}
else
{
return m_num1 / m_num2;
}
//如果想扩展新的功能,需求修改源码
//在真是开发中提倡开闭原则
//开闭原则:对扩展进行开发2,对修改代码进行关闭
}
int m_num1;
int m_num2;
};
void test02()
{
//创建计算器操作数
Calculator c;
c.m_num1 = 10;
c.m_num2 = 10;
cout << c.retResult("+");
}
//利用多态实现计算器
class AbstractCalculator
{
public:
virtual int getResult()
{
return 0;
}
int m_num1;
int m_num2;
};
//加法计算器
class AddCalulator:public AbstractCalculator
{
public:
int getResult()
{
return m_num1 + m_num2;
}
};
//加法计算器
class SubCalulator :public AbstractCalculator
{
public:
int getResult()
{
return m_num1 - m_num2;
}
};
//乘法计算器
//加法计算器
class MultCalulator :public AbstractCalculator
{
public:
int getResult()
{
return m_num1 * m_num2;
}
};
void test03()
{
//多态的使用条件
//父类指针或者引用指向子类对象
//加法运算
AbstractCalculator* abc = new AddCalulator;
abc->m_num1 = 10;
abc->m_num2 = 10;
cout << abc->m_num1 << "+" << abc->m_num2 << " = " << abc->getResult() << endl;
delete abc;
}
int main()
{
test01();
test03();
}
2.虚析构和纯虚析构
虚析构函数和纯虚析构函数区别在哪里?作为两点介绍:
1、虚析构函数:
主要作用是为了来解决基类指针指向派生类对象,并用基类指针释放派生类对象。也就是说父类的虚析构函数,会调用派生类的析构函数。有虚析构函数的类是抽象类,不能实例化对象,不需要在类外实现;
2、纯虚析构函数:
有纯虚析构函数的类它是抽象类,不能实例化对象,而且要在类外实现;
#include
#include
using namespace std;
// 动物类
class Animal {
public:
//纯虚函数
Animal()
{
cout << "animal 构造函数调用" << endl;
}
virtual void speak()=0;//这种写法仅仅适合构建纯虚函数
/*virtual void speak() {
cout << "动物在说话" << endl;
}*/
//利用虚析构可以解决 父类指针释放子类对象不干净的问题
virtual ~Animal()
{
cout << "animal 虚析构函数调用" << endl;
}
/*~Animal()
{
cout << "animal 析构函数调用" << endl;
}*/
//纯虚析构声明也需要实现
//有了纯虚析构之后,这个类也属于抽象类,无法实例化对象
// virtual ~Animal()=0; //这样写会报错,因为这样只是一个声明
};
//纯虚析构
//Animal:: ~Animal()
//{
// cout << "animal 纯虚析构函数调用" << endl;
//}
class Cat :public Animal
{
public:
Cat(string name)
{
cout << "cat 构造函数调用"<speak();
//父类指针在析构函数,不会调用子类中的析构函数,导致子类如果有堆区属性,出现内存泄漏。
delete animal;
}
int main()
{
test01();
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)