C++多态
C++的多态意味着调用成员函数时,会根据调用的对象的类型来执行不同的函数
编译时的多态,编译时就确定了具体的操作过程。
运行时的多态,程序运行过程中才确定的操作过程。
操作的过程即称为联编,也称为绑定。
- 静态联编(早绑定),在编译和连接时确认的。比如函数重载,函数模板。效率高
 
- 动态联编(后期绑定),运行的时候才能确定是哪块代码段。灵活
 
静态联编
函数调用在程序执行前就准备好了
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 48 49 50
   | #include<iostream> #define PI 3.1415926 using namespace std;
  class Point { 	private: 		int x; 		int y; 	public: 		Point(int x=0,int y=0) 		{ 			this->x=x; 			this->y=y; 		} 		double area() 		{ 			return 0.0; 		} };
  class Circle: public Point { 	private: 		int r;     public:     	Circle(int x,int y,int R):Point(x,y)     	{     		this->r=R; 		} 		double area() 		{ 			return r*r*PI; 		} };
  int main() {     Point A(3,3); 	Circle B(3,3,3);   	
  	cout<<A.area()<<endl; 	cout<<B.area()<<endl;
  	Point *ptr;   	ptr = &B;     	cout<<ptr->area()<<endl;
  	return 0; }
   | 
 

第三个cout输出0的原因:编译器在编译时就依据ptr的类型来执行那个are,指针ptr虽然指向了Circle类型的B,但是指针ptr为Point类型,所以执行Point类里的are方法。这里实行的即为静态编译。此时编译器看的是指针的类型而非内容。
动态编译
使用虚函数进行动态联编。程序在任意点可以根据所调用的对象类型来选择调用的函数,这种操作即为动态联编,也成为后期绑定。
虚函数
在基类中使用virtual关键字进行声明的函数。
virtual 函数返回值 函数名(形参)
{
	函数体
}
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 48 49 50
   | #include<iostream> #define PI 3.1415926 using namespace std;
  class Point { 	private: 		int x; 		int y; 	public: 		Point(int x=0,int y=0) 		{ 			this->x=x; 			this->y=y; 		} 		virtual double area() 		{ 			return 0.0; 		} };
  class Circle: public Point { 	private: 		int r;     public:     	Circle(int x,int y,int R):Point(x,y)     	{     		this->r=R; 		} 		double area() 		{ 			return r*r*PI; 		} };
  int main() {     Point A(3,3); 	Circle B(3,3,3);   	
  	cout<<A.area()<<endl; 	cout<<B.area()<<endl;
  	Point *ptr;   	ptr = &B; 	cout<<ptr->area()<<endl; 	cout<<(*ptr).area()<<endl; 	return 0; }
   | 
 

纯虚函数
在基类中不能对虚函数给出有意义的实现,这时侯就使用到了纯虚函数。包含纯虚函数的类是抽象类。抽象类至少包含一个纯虚函数。
定义方式:
virtual 返回值 函数名(形参)  = 0;

虚析构函数
在C++中,不能把构造函数定义为虚构造函数,因为在实例化一个对象时才会调用构造函数,而且虚函数的实现,其实际本质是通过一个虚函数表指针来调用的,还没有对象更没有没内存空间当然无法调用,故没有实例化一个对象之前的构造函数没有意义也不能实现。
析构函数可以为虚函数,而且大多数时候都声明为虚析构函数。这样就可以在基类的指针指向派生类的对象在释放时,可以根据所指向的对象类型动态联编调用子类的析构函数,实现真正的对象内存释放。
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 48
   | #include<iostream> using namespace std;
  class Point { 	private: 	    int x; 	    int y; 	    int *str; 	public: 		Point(int x=0,int y=0) 		{ 			this->x=x; 			this->y=y; 			str = new int[100]; 		} 		~Point() 		{ 			delete []str; 			cout<<"Called Point's Destructor and Delete str !"<<endl; 		} };
  class Circle:public Point { 	private: 		int r; 		int *str; 	public: 		Circle(int x,int y,int r):Point(x,y) 		{ 			this->r=r; 			str = new int[100]; 		} 		~Circle() 		{ 			delete []str; 			cout<<"Called Circle's Destructor and Delete str !"<<endl; 		} }; int main() { 	Point *p; 	p = new Circle(10,10,20); 	delete p;
  	return 0; }
   | 
 

仅调用了基类的析构函数,这样一来派生类中new出来的4*100字节的内存就会残留,造成内存泄漏!
