虛函數、純虛函數、虛函數與析構函數


一、虛函數

只有用virtual聲明類的成員函數,使之成為虛函數,不能將類外的普通函數聲明為虛函數。因為虛函數的作用是允許在派生類中對基類的虛函數重新定義。所以虛函數只能用於類的繼承層次結構中。

     一個成員函數被聲明為虛函數后,在同一類族中的類就不能再定義一個非virtual的但與該虛函數具有相同的參數(包括個數和類型)和函數返回值類型的同名函數。

       根據什么考慮是否把一個成員函數聲明為虛函數?

       ①  看成員函數所在的類是否會作為基類

       ② 看成員函數在類的繼承后有無可能被更改功能,如果希望更改其功能的,一般應該將它聲明為虛函數。

       如果成員函數在類被繼承后功能不需修改,或派生類用不到該函數,則不要把它聲明為虛函數。不要僅僅考慮到作為基類而把類中的所有成員函數都聲明為虛函數。

      應考慮對成員函數的調用是通過對象名還是通過基類指針或引用去訪問,如果是通過基類指針或引用去訪問的,則應當聲明為虛函數。有時在定義虛函數時,並不定義其函數體,即純虛函數。它的作用只是定義了一個虛函數名,具體功能留給派生類去添加。

      說明:使用虛函數,系統要有一定的空間開銷。當一個類帶有虛函數時,編譯系統會為該類構造一個虛函數表(vtbl),它是一個指針數組,存放每個虛函數的入口地址。系統在進行動態關聯的時間開銷很少,提高了多態性的效率。

二、純虛函數

        有時候,基類中的虛函數是為了派生類中的使用而聲明定義的,其在基類中沒有任何意義。此類函數我們叫做純虛函數,不需要寫成空函數的形式,只需要聲明成:

      virtual 函數類型 函數名(形參表列)=0;

       注意:純虛函數沒有函數體;

      最后面的“=0“並不代表函數返回值為0,只是形式上的作用,告訴編譯系統”這是純虛函數”;

      這是一個聲明語句,最后應有分號。

     純虛函數只有函數的名字但不具備函數的功能,不能被調用。在派生類中對此函數提供定義后,才能具備函數的功能,可以被調用。

三、虛析構函數

      析構函數的作用是在對象撤銷之前把類的對象從內存中撤銷。通常系統只會執行基類的析構函數,不執行派生類的析構函數

      只需要把基類的析構函數聲明為虛函數,即虛析構函數,這樣當撤銷基類對象的同時也撤銷派生類的對象,這個過程是動態關聯完成的

      如果將基類的析構函數聲明為虛函數時,由該基類所派生的所有派生類的析構函數都自動成為虛函數,即使派生類的析構函數與基類的析構函數名字不相同。

       最好把基類的析構函數聲明為虛函數,這將使所有派生類的析構函數自動成為虛函數,如果程序中顯式delete運算符刪除一個對象,而操作對象用了指向派生類對象的基類指針,系統會調用相應類的析構函數。

        構造函數不能聲明為虛函數。

例如:

 

#include <iostream>
using namespace std;

class Animal
{
public:
	Animal()
	{
		cout << "Animal::Animal() is called" << endl;
	};
	virtual ~Animal()
	{
		cout << "Animal::~Animal() is called" << endl;
	}
	virtual void eat()
	 { 
	 	cout << "Animal::eat() is called" << endl;
	 }
	virtual void walk()
	{ 
	 	cout << "Animal::walk() is called" << endl;
	}
	/* data */
};
class Dog : public Animal
{
public:
	Dog(int w,int h)
	{
		cout << "Dog::Dog() is called" << endl;
		this->weight=w;
		this->height=h;
	}
	virtual ~Dog()
	{
		cout << "Dog::~Dog() is called" << endl;
	}
	int weight;
	int height;
	void eat()
	{
		cout<<"i eat meat"<<endl;
	}
	void walk()
	{
		cout<<"run"<<endl;
	}
	/* data */
};
 int main(int argc, char const *argv[])
{
	/* code */
	Animal *ani= new Dog(12,23);
	Dog *dog=new Dog(23,34);
	ani->eat();
	ani->walk();
	dog->eat();
	dog->walk();
	delete ani;
	//delete dog;
	return 0;
}

 

 (C++ 析構函數一般定義為虛函數)如果基類中析構函數沒有定義為虛函數,則delete ani的時候,僅僅調用了父類的析構函數,子類的沒有調用,如果在父類和子類的構造函數中都有動態內存分配,那么就會存在內存泄漏的問題。一般析構函數最好都寫成虛函數,尤其是父類。 

 

本文有參考:http://blog.csdn.net/lxnkobe/article/details/23115417

http://blog.csdn.net/richerg85/article/details/9217875

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM