多态(多种形态)是C++面向对象的三大特性之一
多态分为两类:
1.静态多态:函数重载和运算符重载属于静态多态,复用函数名
2.动态多态:派生类和虚函数实现运行时多态(重点)
静态多态和动态多态的区别:
1.静态多态的函数地址早绑定—编译阶段确定函数地址
2.动态多态函数地址晚绑定—运行阶段确定函数地址
3.父类的指针或引用指向子类,满足子类实现虚函数的功能
动态多态满足条件:
1.有继承关系
2.子类要重写父类的虚函数
重写:即函数返回值类型 函数名 参数列表 完全相同
//动态多态的使用
父类的指针或者引用,指向子类对象
*/
#include "pch.h"
#include <iostream>
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 &animal=cat;
//动态多态的使用
//父类的指针或者引用,指向子类对象
animal.speak();
}
void test01() {
cat cat;
dospeak(cat);
}
int main()
{
test01();
}
多态原理
1.多态让您能够将派生类对象视为基类对象,例如:假设你创建了从Mammal派生出的Dog, Cat,Horse类,而Mammal类包含很多适用于这些派生类的成员函数,而其中speak(),就是其中之一。它实现了所有哺乳动物都能发出声音的功能。但是现在我们想让每个派生类都发出特殊的声音:如犬吠,猫叫等。每个派生类都必须能够重写speak()方法的实现。
与此同时,如果有一系列Mammal对象,如有Dog,Cat,Horse,Cow对象的农场,你希望让这些对象发出声音,而无需知道或关心它们的speak()实现。将这些对象都视为哺乳动物而调用方法Mammal.speak()时,便使用了多态。
#include<iostream>
class Mammal
{
public:
Mammal():age(1){}
~Mammal(){}
virtual void speak() const{std::cout<<"Mammal speak!"<<std::endl;}
private:
int age;
};
class Dog:public Mammal
{
public:
void speak() const{std::cout<<"Woof!"<<std::endl;}
};
class Cat:public Mammal
{
public:
void speak() const{std::cout<<"Meow!"<<std::endl;}
};
class Horse:public Mammal
{
public:
void speak() const{std::cout<<"Whinny!"<<std::endl;}
};
class Pig:public Mammal
{
public:
void speak() const{std::cout<<"Oink!"<<std::endl;}
};
int main()
{
Mammal* array[5];
Mammal* ptr;
int choice,i;
for(i=0;i<5;i++)
{
std::cout<<"(1)dog(2)cat(3)horse(4)pig: ";
std::cin>>choice;
switch (choice)
{
case 1:
ptr=new Dog;
break;
case 2:
ptr=new Cat;
break;
case 3:
ptr=new Horse;
break;
case 4:
ptr=new Pig;
break;
default:
ptr=new Mammal;
break;
}
array[i]=ptr;
}
for (int i = 0; i < 5; i++)
{
array[i]->speak();
}
system("pause");
return 0;
}
在编译阶段,无法知道将创建什么类型的对象,因此无法知道将调用哪个speak()方法。ptr指向的对象是在运行阶段确定的,这被称为后期绑定(晚绑定)或运行阶段绑定,与此相对的是静态绑定(早期绑定)或编译阶段绑定。