多态的基本概念
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
// 多态的基本概念
// 多态分为静态多态和动态多态
// 静态多态: 函数重载还运算符重载属于静态多态,服用函数名
// 动态多态: 派生派和虚函数实现运行时多态//静态多态和动态多态的区别
// 静态多态的函数地址早绑定-编译阶段确定函数地址
// 动态多态的函数地址晚绑定-运行阶段确定函数地址// 动态多态满足条件
// 1.有继承关系
// 2.子类重写父类的虚函数
// 重写就是:函数返回值类型 函数名 参数列表 完全相同// 动态多态的使用
// 父类的指针或引用执行子类对象// 动物类
class Animal
{
public:virtual void speak(){cout << "动物在说话" << endl;}};
// 猫类
class Cat :public Animal
{
public:void speak(){cout << "小猫在说话" << endl;}
};// 执行说话的函数// C++中允许父子之间的类型转换,不需要强制类型转换
void doSpeak(Animal &animal)
{animal.speak();
}void test01()
{Cat c;// 属于地址早绑定,在编译阶段确定函数地址// 如果想执行让猫说话,那么这个函数地址就不能提前绑定。// 需要在运行期间绑定,地址晚绑定// 此时用到虚函数的概念,也就是在父类中的函数前加virtual// 此作用是让被调用的类的说话函数优先执行,起始也就是加virtual降低了本身的优先级// 子类中的virtual可写可不写doSpeak(c); // 相当于 Animal &animal = c;
}
void doSpeak(Animal* animal)
{animal->speak();
}
void test02()
{Cat c;doSpeak(&c);
}
int main()
{test01();// 引用test02();// 指针system("pause");return 0;
}
多态的原理剖析
此时该类中储存指向该函数的指针
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
// 多态的原理剖析
class Animal
{
public:virtual void speak(){cout << "动物在说话" << endl;};
};
class Cat :public Animal
{
public://重写之后void speak(){cout << "小猫在说话" << endl;}
};
int main()
{cout << "sizeof(Animal) = " << sizeof(Animal) << endl;system("pause");return 0;
}
多态案例一---- 计算器类
普通写法
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
// 计算器类普通写法
class Calculate
{
public:Calculate(int num1,int num2){this->num1 = num1;this->num2 = num2;}int doWork(string operate){if (operate == "+"){return num1 + num2;}else if (operate == "-"){return num1 - num2;}else if (operate == "*"){return num1 * num2;}// 此种写法如果想增加其它的功能,需要修改源码// 在真正的开发中 提倡 开闭原则// 开闭原则: 对扩展进行开放,对修改进行关闭}int num1;int num2;
};
// 普通写法
void test01()
{Calculate c(10, 20);cout << c.num1 << "+" << c.num2 << " = " << c.doWork("+") << endl;cout << c.num1 << "-" << c.num2 << " = " << c.doWork("-") << endl;cout << c.num1 << "*" << c.num2 << " = " << c.doWork("*") << endl;
}
int main()
{test01();system("pause");return 0;
}
多态写法
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
// 计算器类-多态写法// 多态的好处:
// 1.组织结构清晰
// 2.可读性强
// 3.对于前期和后期扩展以及维护性高// C++开发提倡利用多态设计程序架构,因为多态优点很多
class AbstractCalculate
{
public:int num1;int num2;virtual int calculate(){return 0;}
};
class Add :public AbstractCalculate
{
public:virtual int calculate(){return num1 + num2;}
};
class Del :public AbstractCalculate
{
public:virtual int calculate(){return num1 - num2;}
};
class Cheng :public AbstractCalculate
{
public:virtual int calculate(){return num1 * num2;}
};
void test01()
{// 多态使用条件// 父类指针或引用指向子类对象AbstractCalculate* c = new Add;c->num1 = 10;c->num2 = 20;cout << c->num1 << " + " << c->num2 << " = " << c->calculate() << endl;// 用完记得销魂delete c;c = new Del;c->num1 = 10;c->num2 = 20;cout << c->num1 << " - " << c->num2 << " = " << c->calculate() << endl;delete c;
}
int main()
{test01();system("pause");return 0;
}
纯虚函数和抽象类
在多态中,通常父类中虚函数的实现时毫无意义的,主要是调用子类重写的内容
因此可以将虚函数改为纯虚函数
当类中有了纯虚函数,这个类称为抽象类
抽象类特点:
1.无法实例化对象
2.子类必须重写抽象类中的纯虚函数,否则也属于抽象类
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;// 纯虚函数和抽象类
class Animal
{
public:// 纯虚函数// 只要有一个纯虚函数,这类就称为抽象类// 抽象类特点// 1.无法实例化对象// 2.子类必须重写父类中的纯虚函数,否则无法实例化对象virtual void func() = 0;};
class Cat :public Animal
{
public:void func(){cout << "func函数调用" << endl;}};
void test01()
{//Animal a;//new Animal; //抽象类是无法实例化对象的Cat c;// 子类必须重写父类中的纯虚函数,否则无法实例化对象Animal& animal = c;animal.func();
}
int main()
{test01();system("pause");return 0;
}
多态案例二:制作饮品
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
class AbstraceMakeDrinking
{
public:// 1.煮水virtual void zhuShui() = 0;// 2.冲泡virtual void chongPao() = 0;// 3.倒入杯中virtual void daoRuBeiZhong() = 0;// 4.加入辅料virtual void jiaRuFuLiao() = 0;void makeDrink(){zhuShui();chongPao();daoRuBeiZhong();jiaRuFuLiao();}
};
class kaFei :public AbstraceMakeDrinking
{
public:// 1.煮水virtual void zhuShui(){cout << "煮咖啡水" << endl;}// 2.冲泡virtual void chongPao(){cout << "冲泡咖啡" << endl;}// 3.倒入杯中virtual void daoRuBeiZhong(){cout << "导入咖啡杯中" << endl;}// 4.加入辅料virtual void jiaRuFuLiao(){cout << "加入咖啡辅料" << endl;}
};
void test01()
{AbstraceMakeDrinking* coffee = new kaFei;coffee->makeDrink();delete coffee;
}
int main()
{test01();system("pause");return 0;
}
虚析构和纯虚析构
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
#include<string>
// 虚析构和纯虚析构
// 多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时
//无法调用到子类的析构代码
// 因为父类引用指向子类对象,故在释放空间时调用的是父类的析构函数
// 故使用多态(虚析构或纯虚析构)// 虚析构和纯虚析构的共性:
// 1.可以解决父类指针释放子类对象
// 2.都需要具体的函数实现// 虚析构和纯虚析构的区别:
// 如果是纯虚析构,该类属于抽象类,无法实例化对象// 总结
// 1.虚析构和纯虚析构就是用来解决父类指针释放子类对象
// 2.如果子类中没有堆区数据,可以不写虚析构或纯虚析构
// 3.拥有纯虚析构也属于抽象类
class Animal
{
public:// 纯虚析构virtual void speak() = 0;Animal(){cout << "Animal类构造函数的调用" << endl;}利用虚析构可以解决 父类指针释放子类对象时不干净的问题//virtual ~Animal()//{// cout << "Animal类析构函数的调用" << endl;//}// 纯虚析构(需要声明也需要实现)// 有了纯虚析构之后,这个类也属于抽象类,无法实例化对象virtual ~Animal() = 0;
};
// 子类中需要析构函数释放空间,但是多态走不到子类中的析构函数,
// 所以需要虚析构和纯虚析构
Animal:: ~Animal()
{cout << "Animal类析构函数的调用" << endl;
}
class Cat :public Animal
{
public:string* name;Cat(string name){cout << "Cat类构造函数的调用" << endl;this->name = new string(name);}~Cat(){cout << "Cat类析构函数的调用" << endl;if (name != NULL){delete name;name = NULL;}}virtual void speak(){cout << *name << "小猫在说话" << endl;}
};
void test01()
{// 多态:父类指针或引用指向子类对象// 引用:给变量取别名Animal *animal = new Cat("Tom");animal->speak();// 父类指针在析构的时候,不回调用子类中析构函数,// 导致子类如果有堆区属性,出现内存泄露delete animal;animal = NULL;
}
int main()
{test01();system("pause");return 0;
}
// 父类指针在析构的时候,不回调用子类中析构函数,
// 导致子类如果有堆区属性,出现内存泄露
// 解决方法,将父类析构函数改为虚析构或纯虚析构
多态案例三: 电脑组装
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
// CPU抽象类
class Cpu
{
public:virtual void calculate() = 0;
};
// 显卡抽象类
class DisplayCard
{
public:virtual void display() = 0;
};
// 内存抽象类
class Memory
{
public:virtual void distory() = 0;
};// 电脑类
class Computer
{
public:// 用来接受每一个零件Computer(Cpu *cpu, DisplayCard *card, Memory *memory){this->cpu = cpu;this->card = card;this->memory = memory;}~Computer(){if (cpu != NULL){delete cpu;cpu = NULL;}if (card != NULL){delete card;card = NULL;}if (memory != NULL){delete memory;memory = NULL;}}// 用来协同每一个零件工作void work(){cpu->calculate();card->display();memory->distory();}
private:Cpu* cpu;DisplayCard* card;Memory* memory;
};// 不同厂商的CPU
class IntelCpu :public Cpu
{
public:virtual void calculate(){cout << "Intel的CPU开始计算了" << endl;}
};
class LevoeCpu :public Cpu
{
public:virtual void calculate(){cout << "Levoe的CPU开始计算了" << endl;}
};// 不同厂商的显卡
class IntelDisplayCard :public DisplayCard
{
public:virtual void display(){cout << "Intel的显卡开始显示了" << endl;}
};
class LevoeDisplayCard :public DisplayCard
{
public:virtual void display(){cout << "Levoe的显卡开始显示了" << endl;}
};//不同厂商的内存条
class IntelMemory :public Memory
{
public:virtual void distory(){cout << "Intel的内存条开始存储了 " << endl;}
};
class LevoeMemory :public Memory
{
public:virtual void distory(){cout << "Levoe的内存条开始存储了 " << endl;}
};void test01()
{// 第一台电脑运行cout << "第一台电脑运行--------------------------" << endl;Cpu* cpu = new IntelCpu;DisplayCard* card = new IntelDisplayCard;Memory* memory = new IntelMemory;Computer *c = new Computer(cpu,card,memory);c->work();delete c;// 第二台电脑运行cout << "第二台电脑运行--------------------------" << endl;c = new Computer(new LevoeCpu, new LevoeDisplayCard, new LevoeMemory);c->work();delete c;c = NULL;
}
int main()
{test01();system("pause");return 0;
}