虚函数进行方法重定义的写法及其调用关系

虚函数进行方法重定义的写法及其调用关系

1、虚函数进行方法重定义的写法

虚函数的作用是在派生类中进行函数的重写,或者说是把基类中继承来的同名同形参同返回类型的虚函数在派生类中进行重写,其中定义虚函数的返回类型、函数名和形参列表必须相同,否则会认为是函数的重载。但有唯一例外的写法:

class Object
{
	public:
	virtual Object* get(){return this;}
};
class Test:public Object
{
	public:
	virtual Test* get(){return this;}
};

其中,静态函数、友元函数、内联函数、构造函数、拷贝构造函数、移动构造函数都不能定义成虚函数,因为静态、友元函数没有this指针、内联函数不能调用、构造函数是用来放置虚表指针。析构函数可以定义成虚函数,因为虚函数是用来重置虚表指针。
只有类的成员函数才能定义成虚函数,因为虚函数只适用于有继承关系的类对象。
如果定义的虚函数要实现动态多态性时,必须使用类的对象指针或引用来调用。
当在类体中声明、在类外定义虚函数时,要在类体中声明,在类外定义时不能定义再加virtual。

2、虚函数的调用
在调用虚函数时,系统会生成一个对象对应的所有虚函数的函数地址构成的虚表,在调用时会检查指针的来源对象,找到对应的虚表,找出要调用的函数并调用。
虚表的构建方法:

#include<iostream>
using namespace std;
class Object
{
	private:
		int val;
	public:
		Object(int x=0):val(x){}
		virtual void fun()
		{
			cout<<"Object::fun"<<endl;
		}
		virtual void show()
		{
			cout<<"Object::show"<<endl;
		}
		virtual void print()
		{
			cout<<"Object::print"<<endl;
		}
};
class Base:public Object
{
	private:
		int num;
	public :
		Base(int x=0):num(x),Object(x+10) {}
		virtual void fun()
		{
			cout<<"Base::fun"<<endl;
		}
		virtual void show()
		{
			cout<<"Base::show"<<endl;
		}
		virtual void menu()
		{
			cout<<"Base::menu"<<endl;
		} 
};
class Test:public Base
{
	private:
		int count;
	public:
		Test(int x=0):count(x),Base(x+10) {}
		virtual void fun()
		{
			cout<<"Test::fun"<<endl;
		}
		virtual void menu()
		{
			cout<<"Test::menu"<<endl;
		}
		virtual void print()
		{
			cout<<"Test::print"<<endl;
		} 
};

void Vshow(Object *obj)
{
	obj->fun();
	obj->show();
	obj->print();
}

int main()
{
	Test t;
	Base b;
	Object o;
	Vshow(&t);
	Vshow(&b);
	Vshow(&o);
	return 0;
}

Object类没有继承其他类,它的虚表就是类体里的虚函数
|Object vtable |
|–|–|
| void Object::fun |
|void Object::show|
|void Object::print|
Base类继承了Object类,虚表也会继承过来,如果有同名虚函数,就要把Object的函数换成Base的函数
| Base vtable |
|–|–|
| void Base::fun |
|void Base::show|
|void Object::print|
|void Base::menu|
Test类继承了Base类,虚表也继承过来,如果有同名虚函数,就要把Base的函数换成Test的函数
| Test vtable |
|–|–|
| void Test::fun |
|void Base::show|
|void Test::print|
|void Test::menu|

当取Test类的对象t的地址传到Vshow,调用虚函数时系统会查找指针来源对象的虚表,找到对应的函数地址,就能调用对应的虚函数。Vshow函数的形参类型是Object类型的指针,所以函数体内通过(Object*)能调用的虚函数只能是Object虚表里的函数,当调用不属于Object虚表里的虚函数时编译器会报错。
在这里插入图片描述
当把以上代码作出一点小改动,在Test类内定义一个exam函数,exam用this指针调用虚函数show时,系统会查虚表调用Base类里的虚函数show,再在Base类里的show调用menu函数时,不会调用Base类里的show,而是取调Test类的show。由此可见,只有不管指针如何传递,系统调用虚函数时只会调用指针来源的那个对象的虚表。

#include<iostream>
using namespace std;
class Object
{
	private:
		int val;
	public:
		Object(int x=0):val(x){}
		virtual void fun()
		{
			cout<<"Object::fun"<<endl;
		}
		virtual void show()
		{
			cout<<"Object::show"<<endl;
		}
		virtual void print()
		{
			cout<<"Object::print"<<endl;
		}
};
class Base:public Object
{
	private:
		int num;
	public :
		Base(int x=0):num(x),Object(x+10) {}
		virtual void fun()
		{
			cout<<"Base::fun"<<endl;
		}
		virtual void show()
		{
			cout<<"Base::show"<<endl;
			this->menu();
		}
		virtual void menu()
		{
			cout<<"Base::menu"<<endl;
		} 
};
class Test:public Base
{
	private:
		int count;
	public:
		Test(int x=0):count(x),Base(x+10) {}
		virtual void fun()
		{
			cout<<"Test::fun"<<endl;
		}
		virtual void menu()
		{
			cout<<"Test::menu"<<endl;
		}
		virtual void print()
		{
			cout<<"Test::print"<<endl;
		} 
		void exam(){this->show();}
};

int main()
{
	Test t(10);
	t.exam();
	return 0;
}
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_200_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值