多态是指同一名字的事物可以完成不同的功能。多态可以分为编译时的多态和运行时 的多态。前者主要是指函数重载、对重载函数的调用,在编译时就能根据实参确定应 该调用哪个函数。后者则和继承、虚函数等概念相关。 通过基类指针实现多态: 派生类对象的地址可以赋值给基类指针。对于通过基类指针调用基类和派生类中 都有的同名、同参数表的虚函数语句,编译时并不确定要执行的是基类还是派生 类的虚函数,而当程序运行到该语句时,如果基类指针指向一个基类对象,则基 类的虚函数被调用,如果基类的指针指向一个派生类对象,则派生类虚函数被调 用。这种机制就叫做多态。 通过基类引用实现多态: 通过基类的引用调用虚函数的语句也是多态的。 虚函数: 在函数声明前加上virtual关键字的成员函数。virtual关键字只在类定义中的成员函 数声明处使用,不能再类外部写成员函数体时使用。 静态成员函数不能是虚函数。 包含虚函数的类称为多态类。 多态的作用: 在面向对象的程序设计中,使用多态能够增加程序的可扩充性,即程序需要修改或增加功能 时,只需改动或增加较少的代码。此外,使用多态也能够起到精简代码的作用。
#include <iostream> #include <string> using namespace std; class fruit{ private: double price; public: virtual void Print(){ cout << "Base Class" << endl; } }; class apple:public fruit{ private: string area; public: virtual void Print(){ cout << "Derived Class" << endl; } }; int main() { fruit f; apple a; fruit *pf1 = &f; fruit *pf2 = &a; fruit &pf3 = a; pf1->Print(); pf2->Print(); pf3.Print(); return 0; } /* 输出结果: Base Class Derived Class Derived Class */关于多态的主意事项: 类的成员函数之间而已互相调用。在成员函数(静态成员函数、构造函数和析构函数除外)中 调用其它虚成员函数的语句时多态的。
#include <iostream> using namespace std; class fruit{ public: void fun(){ Print(); } virtual void Print(){ cout << "Base Class" << endl; } }; class apple:public fruit{ public: virtual void Print(){ cout << "Derived Class" << endl; } }; int main() { apple a; a.fun(); // 输出:Derived Class // 由于a是一个apple类对象,所以调用的是apple中的Print函数 return 0; }在构造函数和析构函数中调用虚函数: 在构造函数和析构函数中调用虚函数不是多态,因为编译时即可确定调用的是哪个函 数。如果本类中有该函数,调用的就是本类中的函数;如果本类中没有,调用的就是 直接基类的函数;如果直接基类中没有,就调用间接基类中的,以此类推。 注意区分多态和非多态的情况: 要注意,通过基类指针或引用调用成员函数的语句,只有当该成员函数时虚函数时才 会是多态。如果该成员函数不是虚函数,那么这条函数调用语句就是静态联编的,编 译时就能确定调用的时哪个类的成员函数。 C++规定,只要基类中某个函数被声明为虚函数,则派生类中的同名、同参数表的成员函数 即使前面不加virtual关键字,也自动成为虚函数。
虚析构函数: 有时我们会将基类指针指向一个用new运算符动态生成的派生类对象,在释放该对象时是 通过释放指向它的指针实现的。这时,由于delete语句时静态编联的,编译器在此处无 法此时这个指针是指向哪个对象的,只会根据指针是基类类型,而调用基类的析构函数, 从而造成程序的问题。这时,我们可以通过将基类的析构函数声明为虚函数来解决这个 问题。
#include <iostream> using namespace std; class fruit1{ public: ~fruit1(){ cout << "Base Class" << endl; } }; class apple1:public fruit1{ public: ~apple1(){ cout << "Derived Class" << endl; } }; class fruit2{ public: virtual ~fruit2(){ cout << "Base Class" << endl; } }; class apple2:public fruit2{ public: virtual ~apple2(){ cout << "Derived Class" << endl; } }; int main() { fruit1 *pf = new apple1; delete pf; fruit2 *p_f = new apple2; delete p_f; return 0; } /* 输出结果: Base Class Derived Class Base Class */纯虚函数和抽象类: 纯虚函数就是没有函数体的虚函数。包含纯虚函数的类就叫做抽象类。 纯虚函数的写法就是在函数声明后加"=0" 抽象类不能独立生成对象。 抽象类的作用: 抽象类可以作为基类,用来派生新类。可以定义抽象类的指针或引用,并让它们指向或引 用抽象类的派生类的对象,为多态的实现提供条件。独立的抽象类的对象不存在,但是包 含在派生类对象中的抽象类的对象是可以存在的。 如果一个类从抽象类派生而来,当且仅当它对基类中的所有纯虚函数都进行覆盖并都写出函数 体,它才能成为非抽象类。
class fruit1{ // 抽象类 public: virtual void Print() =0; // 纯虚函数 };
转载于:https://www.cnblogs.com/lnlin/p/7637878.html