關於虛擬函式的一些理解

最爱丁珰發表於2024-06-27

經過多次試驗,我發現虛擬函式應該是這個意思

對於任何一個類,無論是不是虛擬函式,所繫結的函式都是這個類裡面的函式(這個叫做“隱藏”),比如下面的程式碼

class A
{
	public:
		void f()
		{
			cout<<1<<endl;
		}
		void g()
		{
			cout<<2<<endl;
		}
		virtual void h()
		{
			f(),g();
		}
};

在這個類裡面,h()中的f()g()指的就是類A的f()g()

class B:public A
{
	public:
		void f()
		{
			cout<<3<<endl;
		}
		void g()
		{
			cout<<4<<endl;
		}
		void h()
		{
			f(),g();
		}
};

在這個類裡面,h()中的f()g()指的就是類B的f()g()

那麼如果我們在主函式中的程式碼如下:

int main()
{
	A *p=new B;
	p->h();
	return 0;
}

預期輸出結果是3 4,而不是1 2。因為這裡看起來是fg都不是虛擬函式了,應該呼叫類A的fg了,實際上並不是這樣。由於我們的指標型別是A *,所以對於這一行程式碼p->h();,我們實際上呼叫的是A::h()(儘管這個指標指向的是類B物件),然而在我們發現A::h()是虛擬函式後,我們就考慮指標指向的物件,發現是類B物件,而這個類裡面還有一個函式B::h(),於是我們重新呼叫B::h();而B::h()會呼叫B::f()B::g(),而我們發現這兩者都不是虛擬函式,於是輸出3 4

但是對於如下程式碼(在類B中加上了域解析符,並將f說明為虛擬函式):

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=2e5+10;
class A
{
	public:
		virtual void f()
		{
			cout<<1<<endl;
		}
		void g()
		{
			cout<<2<<endl;
		}
		virtual void h()
		{
			f(),g();
		}
};
class B:public A
{
	public:
		void f()
		{
			cout<<3<<endl;
		}
		void g()
		{
			cout<<4<<endl;
		}
		void h()
		{
			A::f(),g();
		}
};
int main()
{
	A *p=new B;
	p->h();
	return 0;
}

輸出是1 4,注意此時加了域解析符的函式一定採用靜態繫結

再來看看下面的程式碼

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=2e5+10;
class A
{
	public:
		virtual void f()
		{
			cout<<1<<endl;
		}
		void g()
		{
			cout<<2<<endl;
		}
		virtual void h()
		{
			f(),g();
		}
};
class B:public A
{
	public:
		void f()
		{
			cout<<3<<endl;
		}
		void g()
		{
			cout<<4<<endl;
		}
		void h()
		{
			f(),g();
		}
};
class C:public B
{
	public:
		void f()
		{
			cout<<5<<endl;
		}
		void g()
		{
			cout<<6<<endl;
		}
		void h()
		{
			f(),g();
		}
};
class D:public C
{
	public:
		void f()
		{
			cout<<7<<endl;
		}
		void g()
		{
			cout<<8<<endl;
		}
		void h()
		{
			f(),g();
		}
};
int main()
{
	B *p=new D;
	p->h();
	return 0;
}

首先p->h();這一行程式碼呼叫B::h(),然後發現B::h()是虛擬函式,於是考慮指向的物件,為類D物件,於是考慮D::h(),然後呼叫D::f(),發現為虛擬函式,在考慮物件,為類D物件,於是就是呼叫D::f(),對D::g()同理,於是輸出7 8

書上課後習題的t5和t6可以再做一下,答案就存在本機的對應檔案裡面

相關文章