1. 程式人生 > >虛擬函式有關問題分析

虛擬函式有關問題分析

#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));
	//不帶虛擬函式類的大小

}

結果: