1.多态的基本概率:多态分为两类
1.静态多类:函数重载(函数名相同,函数的参数不同)和运算符重载属于静态多态,复用函数名
2.动态多态:派生类和虚拟函数实现运行时多态
静态多类和动态多态的区别:静态多态的函数地址早就绑定,编译阶段确定函数地址
动态多态的函数地址晚绑定,运行阶段确定函数地址
#include<iostream>
using namespace std;
class Animal //动物类
{
public:
virtual void speak()//虚函数:动态多态的函数地址晚绑定,运行阶段确定函数地址
{
cout << "动物在说话" << endl;
}
};
class Cat: public Animal //猫类
{
public:
void speak() // 这一步重写虚函数 此时vfptr指向了 cat的虚函数的地址
//什么叫重写: 函数名 函数类型 参数值完全相同!!
{
cout << "小猫在说话" << endl;
}
};
/*
1.如果我们希望传入什么对象,那么就调用什么对象的参数
2.如果函数地址在编译阶段才能确定,那么是静态编译
3.如果函数地址在运行阶段才能确定,那么是动态编译
*/
void Dospeak(Animal & animal) // Animal & animal = cat
{
animal.speak();
}
/*
多态满足的条件:
1.有继承关系
2.子类重写父类中的虚函数(virtual)
多态的使用:
父类指针过应勇指向子类的对象
*/
void test01()
{
Cat cat;
Dospeak(cat);//我们原本的意思是想让小猫说话,编译的结果是 动物说话 与我们预期的结果不符合
} //如果想执行小猫说话,那么地址就不能提前绑定,需要在运行阶段进行绑定,地址晚绑定,就要运用多态来进行实现
int main() {
test01();
return 0;
}
虚函数的实现原理:
总结:
多态的使用必须满足:1.有继承关系 2.子类重写父类的虚函数
多态的使用条件:父类的指针或者引用指向子类对象 (Animal & animal) = cat
重写的概念:
函数的返回类型 函数名 列表参数完全一致称为重写
2.多态案例—实现简易的计算器
分别利用普通写法和多态技术,设计实现两个操作数的计算器类
多态的优点:
1.代码组织结构清晰
2.可读性强
3.利于前期和后期的拓展以及维护
#include<iostream>
using namespace std;
#include<string>
//普通写法实现计算器
class Cacolator
{
public:
int getresult(string oper)
{
if (oper == "+") { return a + b; }
else if (oper == "-") { return a - b; }
else if (oper == "*") { return a * b; };
} //如果想要扩展新的功能,需要修改源码
//真实的开发中讲究开闭原则 对拓展进行开发,对修改进行关闭
int a;
int b;
};
void test01() {
Cacolator c1;
c1.a = 10;
c1.b = 10;
cout << c1.a << "+" << c1.b << "=" << c1.getresult("+") << endl;
cout << c1.a << "-" << c1.b << "=" << c1.getresult("-") << endl;
cout << c1.a << "*" << c1.b << "=" << c1.getresult("*") << endl;
}
/*----------------------------------------------------------------------------------------------------------------------------------------------------*/
//利用多态进行实现
class AbstractCacolator
{
public:
virtual int getResult( )
{
return 0 ;
}
int m_a;
int m_b;
};
//加法类
class AddCacoltor :public AbstractCacolator
{
public:
int getResult()
{
return m_a + m_b;
}
//int m_a;
//int m_b; 报错的原因!!!!!!!!!!它已经继承了父类的了
};
class SubCacoltor :public AbstractCacolator
{
public:
int getResult()
{
return m_a - m_b;
}
};
void test02()
{
AbstractCacolator * p = new AddCacoltor;//手动在堆区开辟了内存 用完记得删除
p->m_a = 100;
p->m_b = 100;
cout << p->m_a << "+" << p->m_b << "=" << p->getResult() << endl;
delete p;
p = new SubCacoltor;
p->m_a = 100;
p->m_b = 100;
cout << p->m_a << "-" << p->m_b << "=" << p->getResult() << endl;
delete p;
}
int main()
{
//test01();
test02();
return 0;
}
3.多态的纯虚函数
在多态中,通常父类中虚函数的实现是毫无意义的,主要都是调用子类重写的内容
因此可以将虚函数改为纯虚函数
纯虚函数的写法: virtual 返回值类型 函数名(参数列表) =0
当类中有了纯虚函数 这个类也称为 抽象类
抽象类的特点:1.无法实例化对象
2.子类必须重写抽象类的纯虚函数,否则也属于抽象类
#include<iostream>
using namespace std;
class Base
{
public:
virtual void fun() = 0; //纯虚函数
};
class son :public Base
{
public:
virtual void fun() //需要重写虚函数
{
cout << " fun()函数调用 " << endl;
}
};
void test01()
{
Base * p = new son;
p->fun();
}
int main()
{
test01();
//test02();
return 0;
}
4.多态的案例
#include<iostream>
using namespace std;
class Makedrink
{
public://煮水
virtual void boil() = 0;
//冲泡
virtual void brew() = 0;
//倒入杯中
virtual void cup() = 0;
//加入辅料
virtual void putsomething() = 0;
//制作饮品
void dowork()
{
boil();
brew();
cup();
putsomething();
}
};
class tea :public Makedrink
{
public:
virtual void boil() { cout << "煮龙湖山泉" << endl; } //煮水
virtual void brew() { cout << "放入普洱茶" << endl; } //冲泡
virtual void cup() { cout << "倒入茶杯" << endl; } //倒入杯中
virtual void putsomething() { cout << "放点柠檬" << endl; }//加入辅料
};
void Dowork(Makedrink * abs)// Makedrink * abs = tea
{ //多态的使用条件:父类的指针或者引用指向子类对象 (Animal & animal) = cat
abs->dowork();
delete abs;
}
void test()
{
Dowork(new tea); //如果我们希望传入什么对象,那么就调用什么对象的参数
}
int main()
{
test();
return 0;
}
5.多态的虚析构和纯虚析构
多态在使用的时候,如果子类有属性开辟到堆区!!!!! 那么父类指针在释放时无法调用到子类的析构代码
解决方式:将父类的析构函数改为虚析构或者纯虚析构
虚析构和纯虚析构的共性:
1.可以解决父类指针释放子类对象
2.都需要具体函数的实现
区别:
如果是纯虚析构,哪么该类属于抽象类,无法实例化对象
虚析构语法:
virtual ~ 类名 (){}
纯虚析构语法:
virtual ~类名() = 0;
类名::~类名(){}
#include<iostream>
#include<string>
using namespace std;
class Animal
{
public:
Animal()
{
cout << "Animal的构造函数"<<endl;
}
/*virtual ~Animal()//虚析构
{
cout << "Animal的析构函数" << endl;
}*/
//纯虚析构 如果是纯虚析构,哪么该类属于抽象类,无法实例化对象
virtual ~Animal() = 0;
virtual void speak() = 0;
};
Animal::~Animal()//必须得有纯虚析构的实现
{
cout << "Animal的纯虚析构函数" << endl;
}
class Cat :public Animal
{public:
Cat(string name)
{
cout << "cat的构造函数" << endl;
m_name = new string(name); //开辟到堆区
//多态在使用的时候,如果子类有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码,就是为了解决这个问题
}
virtual void speak()
{
cout <<*m_name<< "小猫在说话" << endl;
}
string *m_name;
~Cat()
{
if (m_name != NULL)
{
delete m_name;
m_name = NULL;
}
cout << "cat的析构函数" << endl;
}
};
void test()
{
Animal * p = new Cat("Tom");
p->speak();
delete p;
}
int main()
{
test();
return 0;
}
6.多态案例:计算机
#include<iostream>
using namespace std;
class Cpu{ //Cpu类
public:
virtual void caculate() = 0;//纯虚函数
};
class Videcard{ //显卡类
public:
virtual void display() = 0;
};
class Memory { //内存条
public:
virtual void storage() = 0;
};
class Computer
{
public:
Computer(Cpu* cpu, Videcard* videcard, Memory* memory)
{ //父类的指针指向子类的对象 体现多态的技术
m_Cpu = cpu;
m_Memory = memory;
m_Videcard = videcard;
}
void Dowork()
{
m_Cpu->caculate();
m_Videcard->display();
m_Memory->storage();
}
~Computer()
{ //进行内存释放
if (m_Cpu != NULL) { delete m_Cpu; m_Cpu = NULL; }
if (m_Videcard != NULL) { delete m_Videcard; m_Videcard = NULL; }
if (m_Memory != NULL) { delete m_Memory; m_Memory = NULL; }
}
private:
Cpu * m_Cpu;
Videcard * m_Videcard;
Memory * m_Memory;
};
//intel的零件
class IntelCpu :public Cpu
{
public:
void caculate()
{
cout << "Intel的cpu正在计算" << endl;
}
};
class IntelVidecard :public Videcard
{
public:
void display()
{
cout << "Intel的videcard正在显示" << endl;
}
};
class IntelMemory :public Memory
{
public:
void storage()
{
cout << "Intel的Memory正在存储" << endl;
}
};
//Lenove的零件
class LenoveCpu :public Cpu
{
public:
void caculate()
{
cout << "Lenove的cpu正在计算" << endl;
}
};
class Lenovevidecard :public Videcard
{
public:
void display()
{
cout << "Lenove的videcard正在显示" << endl;
}
};
class LenoveMemory :public Memory
{
public:
void storage()
{
cout << "Lenove的Memory正在存储" << endl;
}
};
void test()
{ //开始组装第一台电脑
cout << "组装第一台intel的电脑" << endl;
Computer* computer1 = new Computer(new IntelCpu, new IntelVidecard, new IntelMemory);
//堆区开辟的内存记得释放,三个零件的在类中使用了析构函数进行释放
computer1->Dowork();
delete computer1;
//开始组装第二台电脑
cout << "------------------------------------------" << endl;
cout << "组装第二台intel的电脑" << endl;
Computer* computer2 = new Computer(new IntelCpu, new IntelVidecard, new LenoveMemory);
computer2->Dowork();
delete computer2;
}
int main()
{
test();
return 0;
}