第49课 多态的概念和意义
1. 函数重写回顾
(1)父类中被重写的函数依然会继承给子类
(2)子类中重写的函数将覆盖父类中的函数
(3)通过作用域分辨符(::)可以访问到父类中的函数
Child c; Parent* p = &c; c.Parent::print(); //从父类中继承 c.print(); //在子类中重写 p->print(); //父类中定义
2. 面向对象中期望的行为
(1)根据实际的对象类型判断如何调用重写函数
(2)父类指针(引用)
①指向父类对象时,则调用父类中定义的函数
②指向子类对象时,则调用子类中定义的重写函数
3. 面向对象中多态的概念
(1)根据实际的对象类型决定函数调用的具体目标
(2)同样的调用语句在实际运行时有多种不同的表现形态
(3)C++语言直接支持多态的概念
①通过使用virtual关键字对多态进行支持
②被virtual声明的函数被重写后具有多态特性
③被virtual声明的函数叫做虚函数
【编程实验】多态初体验(可对比第48课的非多态版本)
#include <iostream> #include <string> using namespace std; class Parent { public: virtual void print() //多态版本,与48课唯一的不同! { cout << "I'm Parent." << endl; } }; class Child : public Parent { public: void print() //虚函数,父类己加virtual,这里不必再写 { cout << "I'm Child." << endl; } }; void how_to_print(Parent* p) { p->print() ; //展现多态的行为 } int main() { Parent p; Child c; //多态,根据实际对象类型来调用虚函数 how_to_print(&p); //I'm Parent. how_to_print(&c); //I'm Child. return 0; }
4. 多态的意义
(1)在程序运行过程中展现出动态的特性
(2)函数重写必须多态实现,否则没有意义
(3)多态是面向对象组件化程序设计的基础特性
5. 理论中的概念
(1)静态联编:在程序的编译期间就能确定具体的函数调用(如函数重载)
(2)动态联编:在程序实际运行后才能确定具体的函数调用(如函数重写)
(3)小结:
①使用父类指针(引用)时,函数前加virtual为动态联编,没加virtual为静态联编。
②使用父类或子类自身声明对象,加不加virtual都是静态联编的。
【实例分析】动态联编与静态联编
#include <iostream> #include <string> using namespace std; class Parent { public: virtual void func() { cout << "Parent: void func()" << endl; } virtual void func(int i) { cout << "Parent: void func(int i): " << i << endl; } virtual void func(int i, int j) { cout << "Parent: void func(int i, int j): " << i << ", " << j << endl; } }; class Child : public Parent { public: void func(int i, int j) { cout << "Child: void func(int i, int j): " << i << ", " << j << endl; } void func(int i, int j, int k) { cout << "Child: void func(int i, int j, int k): " << i << ", " << j << ", " << k << endl; } }; void run(Parent* p) { p->func(1, 2); //展现多态的特性,动态联编 } int main() { Parent p; p.func(); //静态联编 p.func(1); //静态联编 p.func(1, 2); //静态联编 cout << endl; Child c; c.func(1, 2); //静态联编 run(&p); run(&c); cout << endl; Parent* p2 = &c; p2->func(); //动态联编,virtual函数,尽管func()在Child中没有被重写 return 0; }
【编程实验】江湖恩怨
//场景:庄主打老怪 #include <iostream> #include <string> using namespace std; //老怪 class Boss { public: //无名怪招 int fight() { int ret = 10; //威力10 cout <<"Boss::fight(): " << ret << endl; return ret; } }; //老庄主 class Master { public: //八剑齐飞 virtual int eightSwordKill() { int ret = 8; //威力10 cout <<"Master::eightSwordKill(): " << ret << endl; return ret; } }; //少庄主 class NewMaster : public Master { public: //八剑齐飞 int eightSwordKill() { //少庄主对老庄主的八剑齐飞进行改造,练就了双臂的八剑齐飞 //威力大增 int ret = Master::eightSwordKill() * 2; //威力是老庄主的2倍 cout <<"NewMaster::eightSwordKill(): " << ret << endl; return ret; } }; //战场pk void field_pk(Master* master, Boss* boss) { int k = master->eightSwordKill(); int b = boss ->fight(); if(k < b) { cout <<"Master is killed..." << endl; } else { cout <<"Boss is killed..." << endl; } } int main() { Master master; Boss boss; cout <<"Master vs Boss" << endl; field_pk(&master,&boss); cout << endl; cout <<"NewMaster vs Boss" << endl; NewMaster newMaster; field_pk(&newMaster, &boss); return 0; }
/*输出结果
Master vs Boss
Master::eightSwordKill(): 8
Boss::fight(): 10
Master is killed...
NewMaster vs Boss
Master::eightSwordKill(): 8
NewMaster::eightSwordKill(): 16
Boss::fight(): 10
Boss is killed...
*/
6. 小结
(1)函数重写只可能发生在父类与子类之间
(2)根据实际对象的类型确定调用的具体函数
(3)virtual关键字是C++中支持多态的唯一方式
(4)被重写的虚函数可表现出多态的特性