多态:同样的语句再运行时有多种不同的表现形式(根据对象的实际类型来调用相应的函数,不会弱化成父类)
多态性:通过指向子类的父类指针或引用,可以访问子类中的同名覆盖的成员函数。
多态的体现:虚函数的重载
虚函数:根据指针指向的对象的类型,来执行不同类的同名覆盖函数,实现同一语句的不同行为。
虚函数关键字:virtual.
1. 被virtual声明的函数被重写后具有多态性。(通过指向子类的父类指针或引用,可以访问子类中的同名覆盖的成员函数)
2. 被virtual声明的函数叫虚函数。
3. 对可能要在继承时被重写的函数声明virtual 关键字。
#include <iostream> #include <string> using namespace std; class Parent { public: virtual void print() // 定义为虚函数 { cout << "I'm Parent." << endl; } }; class Child : public Parent { public: void print() // 通过继承的到多态属性(虚函数)等价于 --> virtual void print() { cout << "I'm Child." << endl; } }; void how_to_print(Parent* p) { p->print(); // 同一语句不同的行为(根据p指向的对象调用相应的函数) } int main() { Parent p; Child c; how_to_print(&p); // I'm Parent. 定义print为虚函数后,再调用how_to_print时会根据形参的类型(p-->Parent)调用相应的函数 Parent->print() how_to_print(&c); // I'm Child. c-->Child Child->print() // 没有实现虚函数时,会根据how_to_print(Parent)的实参的类型来调用 Parent->print() return 0; }
多态的意义:
1. 多态是动态的意义,编译时无法预知实际调用,再运行时才展现具体的调用。
2. 重写函数必须用多态来实现。(避免无法访问子类的重写函数)
静态联编:在程序的编译器就决定具体的函数调用。函数重载
动态联编:在程序的执行期才决定具体的函数调用。虚拟函数的重写
#include <iostream> #include <string> using namespace std; class Parent { public: virtual void func() // 虚函数 {} virtual void func(int i) {} virtual void func(int i, int j) {} }; class Child : public Parent { public: void func(int i, int j) // 通过继承也变成虚函数 {} void func(int i, int j, int k) // 通过继承也变成虚函数 {} ; void run(Parent* p) { p->func(1, 1); // 展现多态的特性 // 动态联编 } int main() { Parent p; p.func(); // 静态联编 p.func(1); // 静态联编 p.func(1, 1); // 静态联编 Child c; c.func(1, 1); // 静态联编 run(&p); // 动态联编 打印父类函数 run(&c); // 动态联编 打印子类函数 return 0; }
函数覆盖:通过对象访问子类函数。通过作用域符,指针访问父类函数。
函数重写:通过对象访问子类函数。通过作用域符,指针访问父类函数。
函数多态:根据具体对象访问子类和父类函数。