經過多次試驗,我發現虛擬函式應該是這個意思
對於任何一個類,無論是不是虛擬函式,所繫結的函式都是這個類裡面的函式(這個叫做“隱藏”),比如下面的程式碼
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
。因為這裡看起來是f
和g
都不是虛擬函式了,應該呼叫類A的f
和g
了,實際上並不是這樣。由於我們的指標型別是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可以再做一下,答案就存在本機的對應檔案裡面