虛擬函式有關問題分析
阿新 • • 發佈:2019-02-02
#include<stdio.h> #include<iostream> using namespace std; class FOO { public: void func1(){ printf("func1\n"); }; virtual void func11(){ printf("func11\n"); } void func2(){ printf("func2\n"); } virtual void func3(){ printf("func3:%d\n",data1); } int data1; static int data2; }; int FOO::data2=1; class aFOO:public FOO{ public: void virtual func1(){ printf("afunc1\n"); } void func11(){ printf("afunc11\n"); } void func2(){ printf("afunc2\n"); } void func3(){ printf("afunc3:%d\n",data1); } virtual void func4(){ printf("afunc4\n"); } }; class bFOO:public aFOO{ public: void func1(){ printf("bfunc1\n"); } void func11(){ printf("bfunc11\n"); } void func2(){ printf("bfunc2\n"); } void func3(){ printf("bfunc3:%d\n",data1); } void func4(){ printf("bfunc4\n"); } }; int main(void) { FOO *p=new FOO(); FOO *t=new aFOO(); FOO *s=new bFOO(); cout<<"帶有虛擬函式類的大小"<<endl; cout<<sizeof(FOO)<<endl; cout<<sizeof(aFOO)<<endl; cout<<sizeof(bFOO)<<endl; cout<<"虛擬函式指標改變前的情況"<<endl; p->data1=0; p->func1(); p->func2(); p->func11(); p->func3(); t->data1=1; t->func1(); t->func11(); t->func3(); ((aFOO *)t)->func4(); s->data1=2; s->func1(); ((aFOO *)s)->func1(); s->func2(); s->func11(); ((aFOO *)s)->func11(); s->func3(); ((aFOO *)s)->func4(); cout<<"虛擬函式指標改變後的情況"<<endl; int *tt = (int *)(t); int *ss = (int *)(s); tt[0] = ss[0]; p->data1=0; p->func1(); p->func2(); p->func11(); p->func3(); t->data1=1; t->func1(); t->func11(); t->func3(); ((aFOO *)t)->func4(); s->data1=2; s->func1(); s->func2(); s->func11(); s->func3(); FOO *n=(FOO*) malloc(sizeof(FOO)); n->data1=1; n->data2=2; cout<<n->data1<<endl; cout<<n->data2<<endl; //n->func11();//錯誤 }
輸出結果:
分析:
(1)malloc和new的區別,malloc只分配記憶體,new不僅分配記憶體,還執行建構函式。
(2)如果一個類中包含了虛擬函式,那麼它的每個物件就有一個虛擬函式表,用一個指標vptr指向這個虛表,虛表中的每一項指向一個虛擬函式(你上面的例子只有一個虛擬函式,所以虛表就一項)
(3)這個虛表的建立是在建構函式中完成的(這個過程我們看不到)
(5)要想實現虛擬函式的特性,必須將基類函式定義為虛擬函式,帶有虛擬函式的子類函式不加virtual修飾符也具有虛擬函式的特性
#include<stdio.h> class D{}; class E{int c;}; class A{ public: virtual f1(){ printf("A::f1()\n"); } f2(){ f1(); } }; class B:public A{ public: f1(){ printf("B::f1()\n"); } f2(){ f1(); } }; void main(){ A *a=new B(); a->f2(); A &aa=B(); aa.f2(); A a3=B(); //呼叫拷貝建構函式 a3.f2(); A *a4=&B(); a4->f2(); printf("%d\n",sizeof(D)); //空類大小是1 printf("%d\n",sizeof(E)); //不帶虛擬函式類的大小 }
結果: