C++多态之虚函数
1)什么是虚函数
多态性主要通过虚函数(virtual functions)实现,它允许派⽣类重写基类中的⽅
法,从⽽在运⾏时根据对象的实际类型来调⽤相应的函数。
实现原理
#include<iostream> #include<string> using namespace std; class animal { public: virtual void runing() { cout<<"i can run"<<endl; } virtual void talk() { cout<<" i can talk"<<endl; } }; //派生类继承了父类,父类中的虚函数 在派生类即使被重写了,该函数仍然是虚函数。 class cat :public animal { public: virtual void runing() // 派生类中对父类的虚函数进行重新实现,该函数不管加不加virtal关键字修饰,它都是虚函数,一般建议加上。 { cout<<" i can run fast"<<endl; } //重写:在派生类中对父类的同名成员函数 进行重新实现, 重载:在同一个作用域下,编写多个同名函数,要确保这些函数要么形参或类型不一样 virtual void talk() { cout<<" i can talk by cat language"<<endl; } }; class dog :public animal { public: //在派生类重写父类中虚函数时 加上是一个好习惯。 virtual void runing() override //如果派生类中重写的成员函数如果加了这个关键字override修饰,在编译的时候 它会自动取检测父类是否存在该虚函数 如果不存在就报错,如果存在则放行 { cout<<" i can run and jump"<<endl; } virtual void talk()override { cout<<" i can talk by dog language"<<endl; } }; void test(animal &per) //动态多态是建立在继承的基础之上,没有继承就没有多态。 { per.runing(); //per.talk(); } //实现多态的条件:1.需要在基类中定义虚函数 2.在派生类中对父类的虚函数实现重写 3.多态的接口需要用父类的指针或父类的引用类型 4.派生类需要采用公有继承 int main() { cat s1; dog s2; test(s1); test(s2); /* 不同对象s1,s2 调用相同接口runing()所表现出的不同行为 i can run fast i can run and jump 这个就叫做多态 */ return 0; }#include<iostream> #include<string> using namespace std; class bird { public: virtual void fly() final //final修饰父类的虚函数,就表示该成员函数不允许在派生类中得到重写。final关键字可以阻断派生类对它所修饰的虚函数进行重写 { cout<<" i can flying"<<endl; } }; class tuo_bird:public bird { public: // virtual void fly() // { // // // } }; int main() { tuo_bird s1; //s1.fly(); s1.fly(); return 0; }#include<iostream> #include<string> using namespace std; class bird { public: //纯虚函数的定义格式:virtual 返回类型 函数名([形参列表])=0; 特点:它是一个没有函数体的函数,靠派生类来实现 //抽象类:如果一个类中存在纯虚函数,那么该类就变成了 抽象类 //抽象类特点:不可以通过抽象类构建对象 virtual void fly()=0; //virtual void myfly()=0; }; class parrot:public bird //如果派生类继承了抽象类 如果在派生类中没有对父类中的纯虚函数进行重写,那么该派生类也是抽象类 { public: void fly() //派生类但凡对父类中的任何一个纯虚没有实现 派生类仍然是抽象类 { cout<<" i can fly"; } }; int main() { parrot ss; cout<<sizeof(ss);//8 ---一个类中存在虚函数,会造成该类创建的对象 会多占用对象一个指针大小的空间。 return 0; }#include<iostream> #include<string> using namespace std; class bird { public: virtual void fly() { cout<<"fly from bird"; } virtual ~ bird() { cout<<"bird 析构函数"<<endl; } }; class parrot:public bird //如果派生类继承了抽象类 如果在派生类中没有对父类中的纯虚函数进行重写,那么该派生类也是抽象类 { public: void fly() //派生类但凡对父类中的任何一个纯虚没有实现 派生类仍然是抽象类 { cout<<" i can fly"; } ~parrot() { cout<<"parrot"<<endl; } }; int main() { //当用父类的指针指向一个派生类对象时,此时 如何对该地址施加一个delete 会造成内存泄漏。 bird * s1=new parrot; delete s1; return 0; }菱形继承
#include<iostream> #include<string> using namespace std; //菱形继承:会造成最底层的派生类保存两份最上层类的数据成员,从而造成数据冗余和内容浪费,采用虚继承。virtual可以用来修饰类中的成员函数,也可以修饰继承方式 class A { public: //int a; double arr[5]; }; class B: virtual public A { public: int b; }; class C : virtual public A { public: int c; }; class D: public B, public C { //public: // int d; }; int main() { D dd; cout<<sizeof(dd);//通过虚继承 可以让最底层类 只保留一份最上层类的数据成员,但是我们也付出了代码,也要维护指针占用的空间。 return 0; }