一、多态
1.是什么?
一句话:有多个相同名字的函数,当调用时,会根据调用时的方式不同,调用不同的函数
2.静态多态
以下代码,是一个有2个相同名字,但参数不同的函数组成,这样就形成了重载
当调用函数时,到底用哪个,要根据调用时的参数而确定
#include <iostream>
using namespace std;
int Add(int a, int b) {
cout << "int类型的函数被调用\n";
return a + b;
}
double Add(double a, double b) {
cout << "double类型的函数被调用\n";
return a + b;
}
int main() {
Add(10, 20);
Add(10.0, 20.0);
return 0;
}
3.动态多态
看下面的代码,f->show()到底调用哪个类中的show函数?
#include<iostream>
using namespace std;
class Father {
public:
void show() {
cout << "father show" << endl;
}
};
class Children : public Father {
public:
void show() {
cout << "children show" << endl;
}
};
int main() {
Father *father = new Father();
father->show(); // 调用父类的show函数
Children *children = new Children();
children->show(); // 调用子类的show函数
Father *p = new Children();
p->show(); // 调用哪个类中的show函数?
return 0;
}
p ->show() 调用 Father的
虽然指向子类,但他是父类型定义的指针变量
通过父类指针去调用成员函数时,编译器只会根据指针的类型(这里是父类指针)来决定调用哪个函数,而不会考虑实际指向的对象类型(这里实际指向的是子类对象)。这种现象称为多态中的静态联编。
如果希望调用子类中重写的函数,需要将父类中的 show 函数声明为虚函数,即 virtual void show() { cout << “father show” << endl; } 。这样就可以实现动态多态性,通过父类指针调用子类重写的函数。
二、virtual
是什么?
可以让一个函数成为虚函数
有什么用?
通过virtual可以实现真正的多态
虚函数可以在父类的指针指向子类对象的前提下,通过父类的指针调用子类的成员函数
这种技术让 父类的指针 或 引用 具备了多种形态,这就是所谓的多态
最终形成的功能:
如果父类指针指向的是一个父类对象,则调用父类的函数
如果父类指针指向的是一个子类对象,则调用子类的函数
怎样用?
定义虚函数非常简单,只需要在函数声明前,加上 virtual 关键字即可
注意:在父类的函数上添加 virtual 关键字,可使子类的同名函数也变成虚函数
例子1:
#include<iostream>
using namespace std;
class Father {
public:
virtual void show() {
cout << "father show" << endl;
}
};
class Children : public Father {
public:
virtual void show() {
cout << "children show" << endl;
}
};
int main() {
Father *father = new Father();
father->show(); // 调用父类的show函数
Children *children = new Children();
children->show(); // 调用子类的show函数
Father *p = new Children();
p->show(); // 调用哪个类中的show函数?
return 0;
}
#include <iostream>
using namespace std;
class WashMachine {
public:
virtual void wash() {
cout << "洗衣机在洗衣服" << endl;
}
};
class SmartWashMachine : public WashMachine {
public:
virtual void wash() {
cout << "智能洗衣机在洗衣服" << endl;
}
};
int main() {
// 父类指针指向子类对象
WashMachine *w2 = new SmartWashMachine();
w2->wash();
return 0;
}
以一个开枪过程作例子,逐步深入:
第一案例:
基础版本,冗余的
#include <iostream>
using namespace std;
class MP5 {
public:
void fire() {
cout << "开火\n";
this->push_bullet();
}
void push_bullet() {
// 弹出子弹
cout << "弹出子弹\n";
}
};
class AK47 {
public:
void fire() {
cout << "开火\n";
this->push_bullet();
}
void push_bullet() {
// 弹出子弹
cout << "弹出子弹\n";
}
};
class Person {
public:
char *name;
Person(char *name) {
this->name = name;
}
~Person() {
}
void press_trigger(class AK47 *ak47) {
cout << "扣动扳机\n";
ak47->fire();
}
void press_trigger(class MP5 *mp5) {
cout << "扣动扳机\n";
mp5->fire();
}
};
int main() {
class Person laowang("老王");
class AK47 ak47;
class MP5 mp5;
laowang.press_trigger(&ak47);
laowang.press_trigger(&mp5);
return 0;
}
第二个案例:
抽取基类
#include <iostream>
using namespace std;
class Gun {
public:
void fire() {
cout << "开火\n";
this->push_bullet();
}
void push_bullet() {
// 弹出子弹
cout << "弹出子弹\n";
}
};
class MP5 : public Gun {
public:
};
class AK47 : public Gun {
public:
};
class Person {
public:
char *name;
Person(char *name) {
this->name = name;
}
~Person() {
}
void press_trigger(class AK47 *ak47) {
cout << "扣动扳机\n";
ak47->fire();
}
void press_trigger(class MP5 *mp5) {
cout << "扣动扳机\n";
mp5->fire();
}
};
int main() {
class Person laowang("老王");
class AK47 ak47;
class MP5 mp5;
laowang.press_trigger(&ak47);
laowang.press_trigger(&mp5);
return 0;
}
第三个案例:
重写父类函数
#include <iostream>
using namespace std;
class Gun {
public:
void fire() {
cout << "开火\n";
this->push_bullet();
}
virtual void push_bullet() {
// 弹出子弹
cout << "弹出子弹\n";
}
};
class MP5 : public Gun {
public:
void push_bullet() {
// 弹出子弹
cout << "mp5弹出子弹\n";
}
};
class AK47 : public Gun {
public:
void push_bullet() {
// 弹出子弹
cout << "ak47弹出子弹\n";
}
};
class Person {
public:
char *name;
Person(char *name) {
this->name = name;
}
~Person() {
}
void press_trigger(class AK47 *ak47) {
cout << "扣动扳机\n";
ak47->fire();
}
void press_trigger(class MP5 *mp5) {
cout << "扣动扳机\n";
mp5->fire();
}
};
int main() {
class Person laowang("老王");
class AK47 ak47;
class MP5 mp5;
laowang.press_trigger(&ak47);
laowang.press_trigger(&mp5);
return 0;
}
第四个案例:
多态
#include <iostream>
using namespace std;
class Gun {
public:
void fire() {
cout << "开火\n";
this->push_bullet();
}
virtual void push_bullet() {
// 弹出子弹
cout << "弹出子弹\n";
}
};
class MP5 : public Gun {
public:
void push_bullet() {
// 弹出子弹
cout << "mp5弹出子弹\n";
}
};
class AK47 : public Gun {
public:
void push_bullet() {
// 弹出子弹
cout << "ak47弹出子弹\n";
}
};
class Person {
public:
char *name;
Person(char *name) {
this->name = name;
}
~Person() {
}
// void press_trigger(class AK47 *ak47) {
// cout << "扣动扳机\n";
// ak47->fire();
// }
//
// void press_trigger(class MP5 *mp5) {
// cout << "扣动扳机\n";
// mp5->fire();
// }
void press_trigger(class Gun *gun) {
cout << "扣动扳机\n";
gun->fire();
}
};
int main() {
class Person laowang("老王");
class AK47 ak47;
class MP5 mp5;
laowang.press_trigger(&ak47);
laowang.press_trigger(&mp5);
return 0;
}