1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
#include<string> #include<iostream> using namespace std; class animal{ public: virtual void say()=0; virtual void run() { cout << "running" <<endl; } }; class dog:public animal{ public: void say() { cout<<"wang wang ..."<<endl; } virtual void run() { cout << "dog running" <<endl; } }; class jinmao:public dog{ public: void say() { cout << "I am jinmao, wang wang ..." <<endl; } void run() { cout << "jinmao running" <<endl; } }; void say(animal *a){ a->say(); } void run(animal *a){ a->run(); } void dog_run(dog *d){ d->run(); } int main(){ say(new dog()); say(new jinmao()); run(new dog()); run(new jinmao()); dog_run(new jinmao()); return 0; } |
多态玩的就是虚
什么是多态?
函数的形参中定义基类的情况,当然,这里的基类不一定是爷爷类,父亲类也可以,当实际调用时传递的如果是子类,那么,运行时会检查要调用的类的方法在基类(因为形参是基类,所以要参考基类)中是否virtual的,如果不是virtual的,则直接执行基类中的定义(即使当前确实是子类的实例,也不会执行子类的该方法,换言之,就是不允许覆盖,这就是virtual存在的意义,某些语言是直接覆盖的,没法选择不覆盖),如果是virtual的,则根据继承链向下检查,直到查到该方法的最后一个实现,哪怕继承链中的某些子类没有明确写virtual关键字也没关系(换言之,virtual属性是自动、强制继承的,或者说,dog类中的run方法的virtual关键字是多余的);具体实现上可能不是一个一个查,但至少逻辑上是这样的; 如果animal类的run方法不是virtual的,并不意味着子孙类的run方法再也不能添加virtual了,比如:animal的run没有virtual,dog的run使用了virtual,则run(animal *a)函数只能执行animal类中的run,而dog_run(dog *d) 却可以多态, 即: dog_run(new jinmao()) 时打印金毛的跑法
虚函数
就是允许覆盖,多态的实现方式
纯虚函数
就是没有函数的定义,只有声明,子类想不覆盖都不行,除非子类自己不创建对象,期待孙类的继承;
语法上来讲,函数不定义是不行的,但是纯虚函数就是不定义,所以必须明确说明不定义,即: =0 ,如下: (没有 =0 是不行的)
1 |
virtual void say()=0; |
抽象类与接口
c++中没有抽象类,也没有接口,更没有abstract、interface、implements等关键字,有的只有class和virtual
如果一个类中包含了纯虚函数,则该类自然为抽象类;
如果一个类中只包含纯虚函数,则该类相当于接口;