函数重写:(在子类中重写父类中的函数)
父类中被重写的函数 依然会继承 给子类。
子类中重写的函数将覆盖父类中的函数。
通过作用域分辨符 :: 可以访问到父类中的函数。
例如:
#include <iostream> #include <string> using namespace std; class parent { public: void parent_func(int i , int j) { cout << "parent_func(int i , int j)"<<i<<','<<j<<endl; } }; class subClass : public parent { public: void parent_func(int i , int j)//重写父类中的 void parent_func(int i , int j) { cout << "parent_func(int i , int j)"<<i*2<<','<<j*2<<endl; } }; void doPrint(parent *p)//如果是 subClass 声明的对象,将把 subClass类退化为 parent类来处理(C++ 默认) { p->parent_func(1, 2); } int main() { parent p; subClass s; s.parent::parent_func(1,5);//使用作用域分辨符 通过subClass 声明的对象 去调用parent类中的 parent_func(int i , int j)函数 doPrint(&p);//使用 parent类对象 doPrint(&s);//使用subClass类对象 }
运行结果:
parent_func(int i , int j)1,5 parent_func(int i , int j)1,2 parent_func(int i , int j)1,2
面向对象期望的行为:
根据实际的对象类型判断如何调用重写函数。
父类指针(引用)指向
父类对象则调用父类中定义的函数
子类对象则调用 子类中 重写 的函数
也就是说期望 void doPrint(parent *p) 这个函数调用的时候,如果是父类的对象则直接调用父类中的 void parent_func(int i , int j) 输出结果为:parent_func(int i , int j)1,2
如果是子类对象 则调用void parent_func(int i , int j) 输出结果为:parent_func(int i , int j)2,4
就需要在 父类中将void parent_func(int i , int j) 改为:virtual void parent_func(int i , int j) 表明此函数为 虚函数 子类通过继承的关系 也将把void parent_func(int i , int j) 修改为 虚函数
-通过virtual 支持多态(C++ 中实现多态的唯一方法)
-被virtual 声明的函数被重写后具备多态的特性
-被virtual 关键字声明的函数叫做虚函数。
修改代码如下:
#include <iostream> #include <string> using namespace std; class parent { public: virtual void parent_func(int i , int j) { cout << "parent parent_func(int i , int j)"<<i<<','<<j<<endl; } }; class subClass : public parent { public: void parent_func(int i ,int j)//重写父类中的 void parent_func(int i , int j) { cout << "subClass parent_func(int i , int j)"<<i*2<<','<<j*2<<endl; } }; void doPrint(parent *p) { p->parent_func(1, 2); //根据对象类型判断如何调用重写函数。 } int main() { parent p; subClass s; doPrint(&p);//使用 parent类对象 doPrint(&s);//使用subClass类对象 }
运行结果:
parent parent_func(int i , int j)1,2 subClass parent_func(int i , int j)2,4
多态存在的意义:
-多态在程序运行的过程中展现。
-函数重写必须实现多态,否则无意义
-是面向对象 组件化程序设计 的基础特性
静态联编:
在编译的期间就确定了具体的函数调用(重载函数)
动态联编:
在程序运行后才能确定函数的调用(重写函数)
例如:
#include <iostream> #include <string> using namespace std; class parent { public: virtual void func(int i ) { cout << "func(int i )"<<i<<endl; } virtual void func(int i , int j) { cout << "parent func(int i , int j)"<<i<<','<<j<<endl; } virtual void func(int i , int j,int k) { cout << "parent func(int i , int j,int k)"<<i<<','<<j<<','<<'k'<<endl; } }; class subClass : public parent { public: void func(int i , int j) //等价于 virtual void func(int i , int j) { cout << "subClass func(int i , int j)"<<i+j<<endl; } void func() { cout <<" void func()"<<endl; } }; void doPrint(parent *p) { p->func(1, 2); //实现多态特性 } int main() { parent p; subClass s; p.func(1);//静态联编 p.func(1,2);//静态联编 p.func(1,2,3);//静态联编 cout <<endl; s.func(4,5);//静态联编 编译时就知道了调用函数,最终会调用到,subClass 类中的 void func(int i , int j) 函数 doPrint(&p);//展现动态联编 doPrint(&s);//展现动态联编 }
运行结果:
func(int i )1 parent func(int i , int j)1,2 parent func(int i , int j,int k)1,2,k subClass func(int i , int j)9 parent func(int i , int j)1,2 subClass func(int i , int j)3