一、多态的基本语法
多态:静态多态、动态多态
静态多态:函数重载、运算符重载
动态多态:派生类和虚函数实现运行时多态
区别:
静态多态函数地址早就绑定 - 编译阶段确定函数地址
动态多态函数地址晚绑定 - 运行阶段确定函数地址
————————————————
class Animal
{
public:
void speak()
{
cout << "动物在说话。" << endl;
}
};
class Cat :public Animal
{
public:
void speak()
{
cout << "小猫在说话。" << endl;
}
};
void doSpeak(Animal& animal) //父类引用接收子类对象
{ //Animal& animal = cat;
animal.speak();
}
Cat cat;
doSpeak(cat); // ”动物在说话。“ //子父类函数同名,执行的父类的函数
—————————————————
class Animal
{
public:
void virtual speak() //虚函数
{
cout << "动物在说话。" << endl;
}
};
class Cat :public Animal
{
public:
void speak()
{
cout << "小猫在说话。" << endl;
}
};
void doSpeak(Animal& animal) //父类引用接收子类对象
{ //Animal& animal = cat;
animal.speak(); //这个函数地址还不能确定下来,多种形态,
传入对象不同,不同函数确定不同地址
}
Cat cat;
doSpeak(cat); // ”小猫在说话。“ //子父类函数同名,执行的子类的函数(因为virtual)
__________________________
当子类、父类成员函数同名时, 子类对象调用同名函数成员时,
父类的该同名函数前加virtual,则其函数地址在编译阶段才确定,
所以最终调用了子类的同名成员函数
——————————————————————
总结:子类父类存在同名成员函数,通过父类引用或指针调用子类同名函数时,将父类该同名函数声明为virtual,则此时,调用的就是子类对象
(1)、动态多态满足条件:
1、有继承关系
2、子类重写父类虚函数
(2)、动态多态的使用:
父类的指针或者引用,执行子类对象
——————————————————————
#include<iostream>
using namespace std;
class Animal
{
public:
void virtual 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& animal = cat;
animal.speak(); //这个函数地址还不能确定下来,多种形态,传入对象不同,不同函数确定不同地址
}
void test01()
{
Cat cat;
doSpeak(cat);
Dog dog;
doSpeak(dog);
}
int main()
{
test01();
system("pause");
return 0;
}
一、多态的基本语法02(多态原理剖析)
二、多态案例:计算器类
用普通写法和多态技术,实现两个操作数进行运算的计算器类
1、普通实现
#include<iostream>
using namespace std;
#include<string>
//开闭原则:对扩展进行开发,对修改进行关闭
class Calculator
{
public:
int getResult(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;
}
}
public:
int m_Num1;
int m_Num2;
};
void test01()
{
Calculator c;
c.m_Num1 = 10;
c.m_Num2 = 5;
cout << c.m_Num1 << " + " << c.m_Num2 << " = " << c.getResult("+") << endl;
cout << c.m_Num1 << " - " << c.m_Num2 << " = " << c.getResult("-") << endl;
cout << c.m_Num1 << " * " << c.m_Num2 << " = " << c.getResult("*") << endl;
}
int main()
{
test01();
system("pause");
return 0;
}
2、多态实现
多态优点:
(1)、代码组织结构清晰
(2)、可读性强
(3)、利于前期和后期的扩展、维护
——————————————————
abs = new SubCalculator;
abs->m_A = 10;
abs->m_B = 5;
cout << abs->m_A << " - " << abs->m_B << " = " << abs->getResult() << endl;
delete abs; //abs指向堆区开辟内存,用完之后堆区内存销毁,abs 任然是父类指针
——————————————————
每次都要重新赋值,虽然用的是父类指针,但继承下来的成员具体值,确实自己开辟赋值
#inlcude<iostream>
using namespace std;
class AbstractCalculator
{
public:
virtual int getResult()
{
return 0;
}
public:
int m_A;
int m_B;
};
class AddCalculator :public AbstractCalculator
{
public:
int getResult()
{
return m_A + m_B;
}
};
class SubCalculator : public AbstractCalculator
{
public:
int getResult()
{
return m_A - m_B;
}
};
class MulCalculator :public AbstractCalculator
{
public:
int getResult()
{
return m_A * m_B;
}
};
void test02()
{
AbstractCalculator* abs = new AddCalculator;
abs->m_A = 10;
abs->m_B = 5;
cout << abs->m_A << " + " << abs->m_B << " = " << abs->getResult() << endl;
delete abs; //new delete 成套使用
abs = new SubCalculator;
abs->m_A = 10;
abs->m_B = 5;
cout << abs->m_A << " - " << abs->m_B << " = " << abs->getResult() << endl;
delete abs; //abs指向堆区开辟内存,用完之后堆区内存销毁,abs 任然是父类指针
abs = new MulCalculator;
abs->m_A = 10;
abs->m_B = 5;
cout << abs->m_A << " * " << abs->m_B << " = " << abs->getResult() << endl;
delete abs;
}
int main()
{
//test01();
test02();
system("pause");
return 0;
}
.
三、纯虚函数和抽象类
多态中父类虚函数一般毫无意义,主要是通过调用子类重写的内容。
我们可以将虚函数声明为纯虚函数。
纯虚函数特点:
(1)、无法实例化对象
(2)、子类必须重写纯虚函数,否则子类也为抽象类
含有纯虚函数的类,称为抽象类
#include<iostream>
using namespace std;
class Base
{
public:
//纯虚函数
virtual void func() = 0;
};
class Son :public Base
{
void func()
{
cout << "Son func()" << endl;
}
};
void test01()
{
//纯虚函数无法实例化对象
//Base b;
//new Base;
//子类必须重写纯虚函数,否则子类也为抽象类
//Son s; //未重写
Son s;
Base* b = new Son;
b->func();
}
int main()
{
test01();
system("pause");
return 0;
}
.
四、多态案例2:制作饮品
制作饮品的流程:煮水 - 冲泡 - 倒杯 - 加佐料 (抽象类)
制作Coffee: 煮水 - 冲泡 - 倒杯 - 加佐料 (继承抽象类,实例化)
制作Tea: 煮水 - 冲泡 - 倒杯 - 加佐料 (继承抽象类,实例化)
一个抽象基类接口,实现多态(通过基类指针调用派生类,重新定义的纯虚函数)
#include<iostream>
using namespace std;
//制作饮品抽象类
class AbstractDrinking
{
public:
//煮水
virtual void Boil() = 0;
//冲泡
virtual void Brew() = 0;
//倒杯
virtual void PoutInCup() = 0;
//加佐料
virtual void PutSomething() = 0;
void makeDrink()
{
Boil();
Brew();
PoutInCup();
PutSomething();
}
};
//制作咖啡
class Coffee :public AbstractDrinking
{
public:
//煮水
virtual void Boil()
{
cout << "1.煮沸农夫山泉" << endl;
}
//冲泡
virtual void Brew()
{
cout << "2.冲泡咖啡" << endl;
}
//倒杯
virtual void PoutInCup()
{
cout << "3.将咖啡倒入杯中" << endl;
}
//加佐料
virtual void PutSomething()
{
cout << "4.加入糖和牛奶" << endl;
}
};
//制作茶水
class Tea :public AbstractDrinking
{
public:
//煮水
virtual void Boil()
{
cout << "1.煮沸矿泉水" << endl;
}
//冲泡
virtual void Brew()
{
cout << "2.冲泡茶叶" << endl;
}
//倒杯
virtual void PoutInCup()
{
cout << "3.将茶水倒入杯中" << endl;
}
//加佐料
virtual void PutSomething()
{
cout << "4.加入枸杞" << endl;
}
};
void doWork(AbstractDrinking* abs)
{
abs->makeDrink();
delete abs;
}
void test01()
{
doWork(new Coffee);
cout << endl;
doWork(new Tea);
}
int main()
{
test01();
system("pause");
return 0;
}
.
五、虚析构和纯虚析构
在继承中,利用多态时,如果存在子类对象在堆区开辟内存的情况,则通过父类指针调用子类对象时,没有办法释放子类堆区空间。
解决办法:使用虚析构
1、虚析构和纯虚析构共性:
都可以解决父类指针,释放子类对象
都需要有具体的函数实现代码
2、虚析构和纯虚析构区别:
纯虚析构,该类属于抽象类,无法实例化对象
——————————————
Animal* animal = new Cat("花花");
animal->speak();
delete animal; //调用父类析构函数时,不会调用子类析构函数
//导致子类堆区内容无法释放
——————————————————
将父类Animal的析构函数声明为virtual之后,
调用父类析构时,也会调用子类析构。
——————————————————
(1)、纯虚析构,有声明,也需要实现(防止有堆区,不释放)
(2)、如果子类没有在堆区开辟内存的情况,可以不写虚析构和纯虚析构。
(3)、拥有纯虚函数的类,也属于抽象类
#include<iostream>
using namespace std;
#include<string>
class Animal
{
public:
Animal()
{
cout << "Animal构造函数调用" << endl;
}
//virtual ~Animal()
//{
// cout << "Animal~虚析构函数调用" << endl;
//}
//纯虚析构,有声明,也需要实现(防止有堆区,不释放)
//有了纯虚析构以后,这个类也属于抽象类,无法实例化
virtual ~Animal() = 0;
public:
virtual void speak() = 0;
};
Animal::~Animal()
{
cout << "Animal的纯虚析构调用" << endl;
}
class Cat :public Animal
{
public:
Cat(string name)
{
m_Name = new string(name);
cout << "Cat构造完成" << endl;
}
~Cat()
{
if (m_Name != NULL)
{
delete m_Name;
m_Name = NULL;
cout << "Cat~析构完成" << endl;
}
}
public:
void speak()
{
cout << *m_Name << "在说话" << endl;
}
public:
string* m_Name;
};
void test01()
{
Animal* animal = new Cat("花花");
animal->speak();
//调用父类析构函数时,不会调用子类析构函数
//导致子类堆区内容无法释放
delete animal;
}
int main()
{
test01();
system("pause");
return 0;
}
六、多态案例3:电脑组装
电脑零件:CPU、显卡、内存条
生产零件厂商:Lenovo、Inter
要求:三种各种厂商零件,通过组装得到一台电脑
————————————————
CPU抽象类:Lenovo的CPU、Intel的CPU
显卡抽象类:Lenovo的显卡、Intel的显卡
内存条抽象类:Lenovo的内存条、Intel的内存条
--------------------------
电脑类(传入抽象类指向的派生类)
{
进行组装;
}
————————————————
#include<iostream>
using namespace std;
//抽象类
class CPU
{
public:
virtual void calculator() = 0;
};
class VideCard
{
public:
virtual void display() = 0;
};
class Memory
{
public:
virtual void storage() = 0;
};
//电脑类
class Computer
{
public:
Computer(CPU* cpu, VideCard* vc, Memory* m)
{
m_cpu = cpu;
m_vc = vc;
m_m = m;
//cout << "Computer 构造了" << endl;
}
~Computer()
{
if (m_cpu != NULL)
{
delete m_cpu;
m_cpu = NULL;
//cout << "cpu 析构了" << endl;
}
if (m_vc != NULL)
{
delete m_vc;
m_vc = NULL;
//cout << "videCard 析构了" << endl;
}
if (m_m != NULL)
{
delete m_m;
m_m = NULL;
//cout << "memory 析构了" << endl;
}
}
public:
//组装
void make()
{
m_cpu->calculator();
m_vc->display();
m_m->storage();
}
private:
CPU* m_cpu;
VideCard* m_vc;
Memory* m_m;
};
//Inter 产商零件
class IntelCpu :public CPU
{
public:
//IntelCpu()
//{
// cout << "Intel cpu 构造了" << endl;
//}
public:
void calculator()
{
cout << "Intel CPU" << endl;
}
};
class IntelVideCard :public VideCard
{
public:
//IntelVideCard()
//{
// cout << "Intel VideCard 构造了" << endl;
//}
void display()
{
cout << "Intel VideCard" << endl;
}
};
class IntelMemory :public Memory
{
public:
//IntelMemory()
//{
// cout << "Intel Memory 构造了" << endl;
//}
void storage()
{
cout << "Intel Memory" << endl;
}
};
//Lenovo 产商零件
class LenovoCpu :public CPU
{
public:
void calculator()
{
cout << "Lenovo CPU" << endl;
}
};
class LenovoVideCard :public VideCard
{
public:
void display()
{
cout << "Lenovo VideCard" << endl;
}
};
class LenovoMemory :public Memory
{
public:
void storage()
{
cout << "Lenovo Memory" << endl;
}
};
void test01()
{
Computer *computer1 = new Computer(new IntelCpu, new IntelVideCard, new IntelMemory);
computer1->make();
delete computer1; //delete computer1时,会调用析构函数
cout << "------------------------" << endl;
Computer* computer2 = new Computer(new LenovoCpu, new LenovoVideCard, new LenovoMemory);
computer2->make();
delete computer2;
cout << "------------------------" << endl;
Computer* computer3 = new Computer(new LenovoCpu, new IntelVideCard, new LenovoMemory);
computer3->make();
delete computer3;
}
int main()
{
test01();
system("pause");
return 0;
}