第六周学习:虚函数和多态

虚函数

  • 类定义中,前面有virtual关键字的成员函数就是虚函数,且只用写在声明中。
  • 构造函数和静态成员函数不能使virtual function

多态表现形式一:

  • 派生类 指针可以赋给基类指针
  • 通过基类指针调用基类和派生类中同名的虚函数时:
  • 1.若该指针指向一个基类对象,那么被调用是基类的虚函数。
  • 2.若该指针指向一个派生类对象,那么被调用的是派生类的虚函数
  • 这种机制叫多态。

多态表现形式二:

  • 派生类对象可以赋给基类引用
  • 基类引用调用基类和派生类中同名虚函数
    1. 若该引用引用一个基类对象,则调用基类虚函数;
    1. 若该引用引用一个派生类对象,调用派生类虚函数;
      -这种机制也就派生。

多态的作用:
能够增强程序的可扩充性,即程序需要修改或增加功能时,需要改动和增加的代码较少。

纯虚函数:
virtual double area() = 0,不是具体的对象。

用基类指针数组存放指向各种派生类对象的指针,然后遍历该数组,就能对各个派生对对象进行各种操作。

比如一个compare函数,比较多个派生类(可能不同)的某个double值:

Father* arr[100];
....
int compare(const void* s1,const void* s2)
{
	double a1,a2;
	Father ** p1;	//因为s1、s2是void*,所以必须得用另外指针获得内容
	Father ** p2;
	p1 = (Father * *) s1; //s1、s2都是指向arr数组的元素,元素就是Father*指针,
	p2 = (Father * *) s2; //故s1、s2是指向指针的指针,所以(Father**)来强制转换
	a1 = (*p1)->area();//(*p1)的类型为Father*,是基类指针
	a2 = (*p2)->area();
	if(a1<a2)
		return -1;
	else if(a1>a2)
		return 1;
	else
		return 0;
	}

另一个example:

class Base{
	public:
		void fun1(){fun2();
		}
		virtual void fun2(){cout<<"base::fun2()\n";
		}
}; 

class Derived:public Base
{
	public:
		virtual void fun2(){cout<<"derived::fun2()\n";
		}
};

int main()
{
	Derived d;
	Base* ptr = &d;
	ptr->fun1();
}

此时输出derived::fun2(),因为基类指针ptr指向派生类,this也是基类指针,所以this->fun2()就是调用派生类的fun2();

在构造函数和析构函数中调用虚函数,不是多态。编译时即可确定,调用的函数是自己的类或基类定义的函数,不会等到运行时才决定调用自己的还是派生的函数。

  1. 派生类和基类中虚函数同名同参数表的函数,不加virtual也是自动成为virtual
class father
{
	public:
		void hello(){cout<<"hello from your father\n";}
		void bye(){cout<<"bye from your father";}
};

class son:public father
{
	public:
		void hello() {cout<<"hello from your son\n";}
		~son() {bye();}
		son(){hello();}
};

class grandson:public son
{
	public:
		void hello() {cout<<"hello from your grandson\n";}
		void bye(){cout<<"byr from your grandson\n";}
		grandson(){cout<<"constructor from your grandson\n";}
		~grandson(){cout<<"destructor from your grandson\n";}
};


int main()
{
	grandson s;
	son* ptr = &s;
	ptr->hello();
	return 0;
}
  1. 首先grandson生成一个对象,则构造函数的顺序是:基类、派生类、派生类2,又基类木有,所以先打印son类的构造函数。son类构造函数调用了hello(),又因为构造函数调用virtual function不会算是多态,所以还是用son的hello函数。
    2.然后son类指针,指向grandson,所以掉用grandson的hello()函数,然后析构从grandson开始。然后到son的析构函数,调用一个bye(),又因为son里没有自己的bye,所以使用的是来自father的virtual bye()(这算一个继承下来的成员函数吧)

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/ZmJ6666/article/details/108606681
今日推荐