一、多态概述

        1.多态按字面的意思就是多种形态。当类之间存在层次结构,并且类之间是通过继承关联时,就会用到多态。C++ 多态意味着调用成员函数时,会根据调用函数的对象的类型来执行不同的函数。
        2.重载函数是多态性的一种简单形式。虚函数允许函数调用与函数体的联系在运行时才进行,称为动态联编。

        3.  冠以关键字 virtual 的成员函数称为虚函数实现运行时多态的关键首先是要说明虚函数,另外,必须用基类指针调用派生类的不同实现版本
        4. 基类指针虽然获取派生类对象地址,却只能访问派生类从基类继承的成员 例如:

#include<iostream>
using namespace std ;
class  Base
{ public :       Base(char xx)  { x = xx; }
                      virtual void who()  { cout << "Base class: " << x << "\n" ; }
   protected:    char x;
} ;
class  First_d : public  Base
{ public :       First_d(char xx, char yy):Base(xx)  { y = yy; }
                      void who()  { cout << "First derived class: "<< x << ", " << y << "\n" ; }
   protected:    char y;
} ;
class  Second_d : public  First_d
{ public :
      Second_d( char xx, char yy, char zz ) : First_d( xx, yy ) { z = zz; } 
      void who()  { cout<<"Second derived class: "<<x<<", "<<y<<", "<<z<<"\n" ; }
  protected:    char z;
} ;
int main()
{ Base  B_obj( 'A' ) ;   First_d F_obj( 'T', 'O' ) ;  Second_d S_obj( 'E', 'N', 'D' ) ;
   Base  * p ;
   p = & B_obj ;    p -> who() ;
   p = &F_obj ;     p -> who() ;
   p = &S_obj ;     p -> who() ;
}
//运行结果
//Base class: A
//First derived class: T,O
//Second derived class: E,N,D

二、虚函数&纯虚函数

          虚函数 是在基类中使用关键字 virtual 声明的函数。在派生类中重新定义基类中定义的虚函数时,会告诉编译器不要静态链接到该函数。
        静态链接 - 函数调用在程序执行前就准备好了。有时候这也被称为早期绑定。

        我们想要的是在程序中任意点可以根据所调用的对象类型来选择调用的函数,这种操作被称为动态链接,或后期绑定

1、纯虚函数声明如下: virtual void FunctionName()=0; 纯虚函数一定没有定义,纯虚函数用来规范派生类的行为,即接口。包含纯虚函数的类是抽象类,抽象类不能定义实例,但可以声明指向实现该抽象类的具体类的指针或引用。
2、虚函数声明如下:virtual ReturnType FunctionName(Parameter) 虚函数必须实现,如果不实现,编译器将报错。

3、对于虚函数来说,父类和子类都有各自的版本。由多态方式调用的时候动态绑定。

4、实现了纯虚函数的子类,该纯虚函数在子类中就编程了虚函数,子类的子类即孙子类可以覆盖该虚函数,由多态方式调用的时候动态绑定。

5、虚函数是C++中用于实现多态的机制。核心理念就是通过基类访问派生类定义的函数。

6、在有动态分配堆上内存的时候,析构函数必须是虚函数,但没有必要是纯虚的。

7、友元不是成员函数,只有成员函数才可以是虚拟的,因此友元不能是虚拟函数。但可以通过让友元函数调用虚拟成员函数来解决友元的虚拟问题。

8、析构函数应当是虚函数,将调用相应对象类型的析构函数,因此,如果指针指向的是子类对象,将调用子类的析构函数,然后自动调用基类的析构函数。

9、派生类应该从它的基类公有派生。
10、必须首先在基类中定义虚函数。
11、派生类对基类中声明虚函数重新定义时,关键字virtual可以不写。
12、一般通过基类指针访问虚函数时才能体现多态性。
13、一个虚函数无论被继承多少次,保持其虚函数特性。
14、虚函数必须是其所在类的成员函数,而不能是友元函数,也不能是静态函数。
15、构造函数、内联成员函数、静态成员函数不能是虚函数。(虚函数不能以内联的方式进行处理)

16、析构函数可以是虚函数,通常声明为虚函数。

三、多态和虚函数示例

#include <iostream>
#include<string>
using namespace std;
class Animal
{
	string name;
public:
	Animal(string a_name):name(a_name){}
	virtual void show(){}
	void show_name()
	{
		cout<< "The name is "<<name<<"."<<endl;
	}
};
class Cat :public Animal
{
	string kind;
public:
	Cat(string a_name,string a_kind):Animal(a_name),kind(a_kind)
	{}
	void show();
};
void Cat::show()
{
	show_name();
	cout<<" It's a "<<kind<<endl;
}
class Dog:public Animal
{
	string kind;
public:
	Dog(string a_name,string a_kind):Animal(a_name),kind(a_kind)
	{}
	void show();
};
void Dog::show()
{
	show_name();
	cout<<" It's a "<<kind<<endl;
}
class Tiger:public Cat
{
public:
	Tiger(string a_name,string a_kind):Cat(a_name,a_kind)
	{}
};
int main()
{
	Animal *p;
	Cat cat("Tom","cat");
	Dog dog("Jerry","Dog");
	Tiger tiger("DuDu","Tiger");
	p=&cat;
	p->show();
	p=&dog;
	p->show();
	p=&tiger;
	p->show();
	return 0;
}
//运行结果:
//The name is Tom. It's a cat.
//The name is Jerry. It's a Dog.
//The name is DuDu. It's a Tiger.

四、学习心得

       多态和虚函数的应用范围很广,我觉得学习了这部分知识点之后,可以让程序更统一,多态使得函数名相同,但是作用效果却不同,虚函数给派生类提供了一个公共的接口,方便派生类实现各自不同的功能。两者和继承相结合使用,会大大提高程序的书写效率,提高程序的可读性。

        总之,在今后的C++设计中,要不断的尝试继承+多态&虚函数,逐渐熟悉他们的用法和适用的环境,做到“信手拈来”,提高自己的编程水平。