【C++】5.4 虚函数

目录

5.4 虚函数

5.4.1 虚函数引入

5.4.2 虚函数的定义

5.4.3 纯虚函数和抽象类

 

  • 5.4 虚函数

虚函数是重载的另一种表现形式,提供了运行时的多态机制

虚函数允许函数调用时与函数体之间的联系在运行时才建立,也就是动态联编

  • 5.4.1 虚函数引入

【虚函数引入示例】

#include<iostream>
using namespace std;

class Base{
	public:
		Base(int sub_x,int sub_y){
			x=sub_x;
			y=sub_y;
		}
		
		void show(){
			cout<<"调用基类Base的show()函数"<<endl;
			cout<<"x = "<<x<<" y = "<<y<<endl;
		}
	private:
		int x;
		int y;
};

class Derived:public Base{
	public:
		Derived(int sub_x,int sub_y,int sub_z):Base(sub_x,sub_y){
			z=sub_z;
		}
	void show(){
		cout<<"调用派生类的show()函数"<<endl;
		cout<<"z = "<<z<<endl;
		
	}
	private:
		int z;
};

int main()
{
	Base base(50,50),*ba;		//定义基类对象base和对象指针ba 
	Derived derived(10,20,30);	//定义派生类对象derived 
	ba=&base;					//基类对象指针指向基类对象base 
	ba->show();					
	
	ba=&derived;				//基类对象指针指向派生类对象derived 
	ba->show();
	
	return 0;
}

【虚函数引入示例运行结果】

 【虚函数引入示例说明】

ba=&derived,ba指向派生类对象,执行语句“ba->show()”调用的仍是基类的同名成员函数show

原因在于:C++中规定基类的对象指针可以指向它公有派生类对象,但只能访问派生类中从基类继承来的成员,而不能访问公有派生类中定义的成员

【虚函数示例】

#include<iostream>
using namespace std;

class Base{
	public:
		Base(int sub_x,int sub_y){
			x=sub_x;
			y=sub_y;
		}
		
		virtual void show(){            //在基类中定义虚函数show
			cout<<"调用基类Base的show()函数"<<endl;
			cout<<"x = "<<x<<" y = "<<y<<endl;
		}
	private:
		int x;
		int y;
};

class Derived:public Base{
	public:
		Derived(int sub_x,int sub_y,int sub_z):Base(sub_x,sub_y){
			z=sub_z;
		}
	virtual void show(){                //在派生类中定义虚函数show
		cout<<"调用派生类的show()函数"<<endl;
		cout<<"z = "<<z<<endl;
		
	}
	private:
		int z;
};

int main()
{
	Base base(50,50),*ba;		//定义基类对象base和对象指针ba 
	Derived derived(10,20,30);	//定义派生类对象derived 
	ba=&base;					//基类对象指针指向基类对象base 
	ba->show();					
	
	ba=&derived;				//基类对象指针指向派生类对象derived 
	ba->show();
	
	return 0;
}

【虚函数示例运行结果】 

5.4.2 虚函数的定义

1、虚函数的定义

【定义】虚函数就是在基类被关键字virtual说明,并在派生类中重新定义的函数

【作用】允许在派生类中重新定义与基类同名的函数,并且可以通过基类指针或引用来访问基类和派生类中的同名函数

【定义方法】

virtual 函数类型 函数名(形参表){
    函数体
}

【说明】

(1)在派生类中重新定义时,其函数原型,包括函数类型、函数名、参数个数、参数类型的顺序都必须与基类中的原型完全相同

(2)若在基类中,只声明虚函数原型需要加上virtual,而在类外定义虚函数时,则不必再加virtual,注意常成员函数声明定义的区别

(3)当一个成员函数被定义为虚函数后,其派生类中符合重新定义虚函数要求的同名函数都自动成为虚函数

(4)如果在派生类中没有对基类的虚构函数重新定义,则公有派生类继承其直接按基类的虚函数,一个虚函数无论被继承多少次,仍然保持其虚函数的特性

(5)虚函数必须是所在类的成员函数,而不能是友元函数,也不能是静态成员函数,因为虚函数调用要靠特定的对象来决定激活哪个函数

(6)只有通过基类指针访问虚函数时才能获得运行时的多态性,而使用点运算符的方式调用虚函数属于静态联编

2、虚析构函数

不能声明虚构造函数,但可以声明虚析构函数

【虚析构函数引入示例】

主函数中用new运算符建立一个派生类的无名对象和定义一个基类的对象指针,并将无名对象的地址赋给这个基类对象指针,当调用delete运算符撤销无名对象时,系统只执行基类的析构函数,而不执行派生类的析构函数

#include<iostream>
using namespace std;

class A{
	public:
		~A(){
			cout<<endl<<"调用基类B的析构函数\n"; 
		}
		
}; 

class B:public A{
	public:
		~B(){
			cout<<endl<<"调用派生类D的析构函数\n";
		}
}; 

int main()
{
	A *p;
	p=new B;
	delete p;
	
	return 0;
}

 【虚析构函数引入示例运行结果】

【虚析构函数示例】 

虽然派生类的析构函数与基类的析构函数名字不同,但是如果将基类的析构函数定义为虚函数,由基类所派生类的所有派生类的析构函数都自动为虚函数

#include<iostream>
using namespace std;

class A{
	public:
		virtual ~A(){
			cout<<endl<<"调用基类B的析构函数\n"; 
		}
		
}; 

class B:public A{
	public:
		~B(){
			cout<<endl<<"调用派生类D的析构函数\n";
		}
}; 

int main()
{
	A *p;
	p=new B;
	delete p;
	
	return 0;
}

  【虚析构函数示例运行结果】

 【虚析构函数格式】

virtual ~类名();

3、虚函数与重载函数的关系

在派生类中重新定义基类的虚函数是重载的另一种形式,但不同一般的函数重载

【普通的函数重载】

其函数的参数或参数类型必须有所不同,函数的返回类型可以不同

【虚函数重载】

(1)要求函数名、返回类型、参数个数、参数的类型和顺序与基类中的虚函数原型完全相同

(2)如果返回类型相同,其余不同,报错;如果函数名相同,而参数个数,参数类型,参数顺序不同,系统将它视为普通函数重载,虚函数特性丢失

【示例】

#include<iostream>
using namespace std;

class Base{
	public:
		virtual void function1();
		virtual void function2();
		void function3();
};

class Derived:public Base{
	public:
		virtual void function1();
		void function2(int x);
		void function3();
};

void Base::function1(){
	cout<<endl<<"Base->function1"<<endl;
}
void Base::function2(){
	cout<<endl<<"Base->function2"<<endl;
}

void Base::function3(){
	cout<<endl<<"Base->function3"<<endl;
}

void Derived::function1(){
	cout<<endl<<"Derived->function1"<<endl;
}

void Derived::function2(int x){
	cout<<endl<<"Derived->function2"<<endl;
}

void Derived::function3(){
	cout<<endl<<"Derived->function3"<<endl;
}

int main()
{
	Base ba,*bp;
	Derived de;
	
	bp=&de;
	bp->function1();
	bp->function2();
	bp->function3();
}




【示例运行结果】

4、多重继承与虚函数

【示例】

#include<iostream>
using namespace std;

class Base1{
	public: 
		virtual void fun(){
			cout<<"---Base1---"<<endl; 
		}
}; 

class Base2{
	public:
		void fun(){
			cout<<"---Base2---"<<endl; 
		}
};

class Derived:public Base1,public Base2{
	public:
		void fun(){
			cout<<"---Derived---"<<endl; 
		}
};


int main()
{	
	Base1 *ba1;
	Base2 *ba2;
	Derived de;
	
	ba1=&de;
	ba1->fun();        //此处的fun为虚函数
	
	ba2=&de;
	ba2->fun();        //此处的为非虚函数
	
}

【示例运行结果】

 

  • 5.4.3 纯虚函数和抽象类

 【定义】纯虚函数是一个在基类中说明的虚函数,它在该基类中没有定义,但要求它的派生类中根据需要对他进行定义,或仍说明为纯虚函数。

【形式】

virtual 函数类型 函数名(参数表)=0;

【示例】

#include<iostream>
using namespace std;

class Area{
	public:
		virtual void calculate()=0;        //纯虚函数
};

class Circle:public Area{
	public:
		Circle(double radius){
			r=radius;
		}
		void calculate(){                   //重新定义纯虚函数
			cout<<endl<<"circle area = "<<3.14*r*r<<endl; 
		}
	private:
		double r;
};

class Square:public Area{
	public:
		Square(double edge){
			e=edge;
		}
		void calculate(){                    //重新定义纯虚函数
			cout<<endl<<"square area = "<<e*e<<endl; 
		}
	private:
		double e;
};

int main()
{
	Area *a1,*a2;
	
	Circle c(10);
	a1=&c;
	a1->calculate();
	
	Square s(10);
	a2=&s;
	a2->calculate();
	
	return 0;
}

【示例运行结果】

【抽象类说明】

如果一个类至少有一个纯虚函数,称该类为抽象类 

(1)抽象类中至少包含一个没有定义功能的纯虚函数,因此抽象类只能用作其他类的基类,不能建立抽象类的对象

(2)抽象类不能用作参数类型、函数返回值、或显示转换的类型

(3)抽象类可以声明指向抽象类的指针变量,此指针指向它的派生类,实现多态性

(4)在抽象类的派生类中没有重新说明纯虚函数,则该函数在派生类中仍然为纯虚函数,这个派生类仍还是一个抽象类

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值