多态
虚函数
先来看一段代码:
#include<iostream> using namespace std; class Animal { public : void run() { cout << "I don't know how to run" << endl; } }; class Cat : public Animal{ public : void run() { cout << "I can run with four legs" << endl; } }; class Bat : public Animal{ public : void run() { cout << "I can fly" << endl; } }; #define P(func) {\ printf("%s : ", #func);\ func;\ } int main() { Cat c; //子类的对象可以隐式的转换为父类的类型 Animal &a = c; Animal *p = &c; P(c.run()); P(a.run()); P(p->run()); return 0; }
a是Animal的引用类行而指向的是c对象,p是Animal的指针类型指向对象c的地址。
那么我们认为的结果应该都是调用Cat类型中的run方法,但是结果却是调用的Animal中的run方法
那么如何完成我们想要的效果呢,把基类中也就是Animal类中的run()方法变为虚函数,在父类中对应函数前加上virtual关键字,再子类中对应的函数后加上override关键字。
class Animal { public : virtual void run() { cout << "I don't know how to run" << endl; } }; class Cat : public Animal{ public : void run() override{ cout << "I can run with four legs" << endl; } }; class Bat : public Animal{ public : void run() override{ cout << "I can fly" << endl; } };
这样过后执行整个代码,就可以得到我们想要的效果了。
这里对应的知识点:
普通成员函数是跟着类型的,比开始时,run方法不是虚函数只是普通的成员函数,那么在对应类类型前调用该函数,执行的就是对应类型中的函数方法,那么Animal &a = c,调用的就是Animal中的run方法,Animal *p = c调用的run方法也是Animal中的run方法。虚函数是跟着对象的,比如在对父类中(Animal类)run方法加上virtual关键字之后,让run方法变为了虚函数,而子类中的run方法也变为了虚函数,执行时调用的对应函数就是对象对应的函数。Animal &a = c对应调用就是对象c的类型中的run方法,同理Animal *p = c调用的run方法也是对象c的类中的run方法。
编译期和运行期
来一段简单的代码理解运行期和编译期
#include<iostream> using namespace std; int main() { int n; scanf("%d", &n); //只有再代码执行时,读入n //才能知道m具体等于几 //所以这是运行期 int m = 2 * n; //在读代码时我们就能准确的知道c等于3 //所以这是编译期 int c = 1 + 2; return 0; }
理解完后再看下面的代码:
#include<iostream> using namespace std; class Animal { public : void say() { cout << " Class Animal" << endl; } }; class Cat : public Animal { public : void say() { cout << " Class Cat" << endl; } }; class Dog : public Animal { pu