韋慶清,崔如春,李 婭(佛山科學技術學院電子與信息工程學院,佛山528000)
虛機制在《面向對象程序設計C++》中的教學方法研究
韋慶清,崔如春,李婭
(佛山科學技術學院電子與信息工程學院,佛山528000)
虛機制是《面向對象程序設計C++》課程的重要學習內容。通過分析虛機制的基本特征,深入探討虛機制的教學重點、教學難點、教學手段及教學方法,并根據該課程的教學特點,給出簡易的應用程序實例,說明虛機制在面向對象程序設計中的實際應用,從而達到提高教學效果并順利完成教學任務的目的。
教學方法;面向對象程序設計;虛機制
《面向對象程序設計C++》是大學本科計算機專業課程,“封裝、繼承及多態”三大基本特征是《面向對象程序設計C++》課程的重要學習內容,而貫穿這三大基本特征的學習則離不開其特有的虛機制對象,因此,從虛機制的基本教學內容出發,正確分析、探討其基本教學特征;把握其教學重點和教學難點;設計、使用恰當的教學手段和教學方法;最后實施并完成好其教學目標是順利完成該課程教學任務的重要保證。
在《面向對象程序設計C++》課程的課堂教學活動過程中,主要圍繞著“封裝、繼承及多態”三大基本特征來展開相關知識內容的教學,而這三大特征的基本特點、基本原理和關鍵實現技術都離不開其特有的虛機制對象,常用的虛機制對象主要有虛函數、虛析構函數和虛基類等[1]。盡管這三個虛機制對象都用一個相同的關鍵字virtual來修飾,但其功能、作用卻完全不同,在面向對象的程序設計過程中,虛函數主要用來實現運行時的多態性;虛析構函數主要用來實現動態聯編,確保調用各析構函數使得在撤銷動態分配空間的同時能得到正確的處理;而虛基類主要用來實現共享繼承以消除多重繼承引起的二義性。因此,在具體的教學活動過程中應分別設計、處理好各虛機制對象的實際教學。
課堂教學是整個課程教學中的重要環節,在這個環節中應該充分利用好課堂的45分鐘時間,盡最大可能發揮好課堂教學的作用。因此,根據各不同的虛機制對象,應選擇恰當的教學方法來完成其課堂教學任務。
2.1虛函數
虛函數,主要圍繞其基本概念、功能及應用等三方面內容進行,重點講解什么是虛函數,該函數有哪些基本特點、基本功能作用和實際應用,難點在于設計恰當的程序代碼以說明虛函數在實際程序設計中的具體應用,并選擇講授法、討論法和演示法作為主要教學方法。虛函數具體的教學過程設計如下:
虛函數(virtual function)就是在一個類中用保留字virtual來定義的非靜態成員函數。基類的虛函數在其派生類中仍然是虛函數,并且一般需要在派生類中重定義。一個含有虛函數的類稱為多態類,無論這些虛函數是繼承下來的還是在派生類中新增加的[2]。在基類中說明虛函數的方法是:
virtual<函數返回類型><函數名>(<參數表>){…}
一個類的虛函數僅對派生類中重定義的函數起作用,而對其他函數沒有影響。在基類中使用虛函數保證通過指向基類的指針調用基類的一個虛函數時,C++編譯系統對該調用進行動態綁定,而使用普通函數則是靜態綁定。
在派生類中重新定義虛函數時,要求函數原型必須與其在基類中的原型(函數返回類型、函數名、函數參數個數及其類型)完全一致。此外,還必須借助于基類指針才得以動態聯編進而實現運行時的多態性。否則,虛函數將按靜態聯編方式調用[3]。
值得注意的是,函數重定義與函數重載不同,它們是兩個不同的概念,具體定義時要注意其區別。以下實例程序代碼說明虛函數在多態中的應用。
#include<iostream.h>
class BASE{
public:
virtual void fun1()
{cout<<"這是基類的虛函數fun1()."<<endl;}//在基類中定義一個虛函數fun1()
virtual void fun2()
{cout<<"這是基類的虛函數fun2()."<<endl;}//在基類中定義另一個虛函數fun2()
void fun3()
{cout<<"這是基類的普通函數fun3()."<<endl;}//在基類中定義一個普通函數fun3()
};
class DERIVED:public BASE{
public:
void fun1()
{cout<<"這是派生類的虛函數fun1()."<<endl;}//在派生類中重定義虛函數fun1()
void fun2(inta)
{cout<<"這是派生類的成員函數fun2()."<<endl;}//在派生類中重載fun2(),虛特性丟失
void fun3()
{cout<<"這是派生類的普通函數fun3()."<<endl;}//在派生類中定義普通函數fun3()
};
voidmain(){
BASE*p;DERIVED d;
p=&d;//定義基類指針指向派生類對象
p->fun1();//調用的是DERIVED::fun1(),動態聯編
p->fun2();//調用的是BASE::fun2(),靜態聯編,虛特性丟失
p->fun3();//調用的是BASE::fun3(),靜態聯編}
程序運行結果如圖1所示:

圖1 虛函數在多態中的應用
由此可見,在面向對象的程序設計中,虛函數是實現運行時多態性不可缺少的前提條件。
2.2虛析構函數
在對虛析構函數所進行的教學活動設計過程中,應把該函數的基本概念和基本功能特征等內容作為教學重點講解,而把設計一個程序實例作為教學難點,用來加以分析說明虛析構函數在類封裝中的實際應用,并選擇講授法、對比法和演示法作為主要教學方法。虛析構函數具體的教學過程設計如下:
什么是虛析構函數?虛析構函數是指在析構函數前加上關鍵字virtual進行說明,則該析構函數稱為虛析構函數。例如:
class A{
virtual~A(){…}//則為類A聲明了一個虛析構函數
…
};
通常,習慣將基類的析構函數聲明為虛析構函數。當基類的析構函數聲明為虛析構函數時,無論指針指的是同類族中的哪一個類對象,系統會采用動態關聯,調用相應的析構函數,對該對象執行清理工作,這樣能更好避免內存泄漏現象[4]。以下程序代碼說明虛析構函數的具體應用。
#include<iostream.h>
class A{
public:
virtual~A(){cout<<"這是類A的虛析構函數"<<endl;} //類A聲明的虛析構函數
//~A(){cout<<"這是類A的析構函數"<<endl;}
};
class B:public A{
public:
B(){ptr=new int[20];}
virtual~B(){//類B聲明的虛析構函數
cout<<"這是類B的虛析構函數"<<endl;
delete[]ptr;
}
//~B(){cout<<"這是類B的析構函數"<<endl;delete[]ptr;} private:int*ptr;
};
intmain(){
A*p=new B;
delete p;
return 0;
}
程序運行結果如圖2所示:

圖2 虛析構函數的應用
如果將上述程序代碼中類A和類B所聲明的虛析構函數改為析構函數,則程序運行結果僅顯示:這是類A的虛析構函數。顯然,在執行delete p;語句時并沒有調用到類B的析構函數,因而引起內存泄漏。所以,通常是將基類的析構函數聲明為虛析構函數,這樣在用delete釋放資源的時候,確保析構函數會被正確調用。
2.3虛基類
虛基類與前面所講授的虛函數、虛析構函數相似。其具體的教學過程設計如下。
為什么要引入虛基類?因為在基于C++的面向對象程序設計的實際應用中,若在多重繼承時沒有作特殊聲明,此時采用的是復制繼承,會導致重復繼承所帶來的二義性問題。下面引入一個程序代碼作分析說明。#include<iostream.h>
class BASE{public:int i;};
class BASE1:public BASE{public:int j;};
class BASE2:public BASE{public:int k;};
class DERIVED:public BASE1,public BASE2{public:int sum;};
void main(){
DERIVED obj;//聲明一個派生類對象
//obj.i=3;//編譯錯誤,編譯程序無法確定使用i的哪一份副本
obj.j=5;//編譯正確,使用從BASE1繼承下來的j
obj.k=7;//編譯正確,使用從BASE2繼承下來的k}
通常,C++語言有兩種方法解決這種二義性問題。第一種方法是采用作用域運算符“::”來解決,但這不是一種很好的解決途徑;另一種方法是使用虛基類機制(Virtual Base Class)來解決。虛基類可以保證在任何派生類中只提供一個基類的副本,達到消除二義性問題的目的。
虛基類是當基類被繼承時,在基類的繼承訪問控制關鍵字前面加上關鍵字virtual來定義的。聲明虛基類的方法是:class派生類:virtual訪問權限修飾符父類名{…};
現使用虛基類將上面程序代碼修改如下:
#include<iostream.h>
class BASE{public:int i;};
class BASE1:virtual public BASE{public:int j;};
class BASE2:virtual public BASE{public:int k;};
class DERIVED:public BASE1,public BASE2{public:int sum;};
void main(){
DERIVED obj;//聲明一個派生類對象
obj.i=3;//編譯正確,
obj.j=5;//編譯正確,使用從BASE1繼承下來的j
obj.k=7;//編譯正確,使用從BASE2繼承下來的k
}
可見,普通基類與虛基類之間的唯一區別只有在派生類重復繼承了某一基類時才表現出來,虛基類用于實現共享繼承。該程序代碼所實現的共享繼承如圖3所示,其相應的對象存儲結構分配如圖4所示:

圖3 共享繼承示意圖

圖4 對象存儲結構分配圖
(1)必須在最新派生出來的派生類的初始化列表中調用虛基類的構造函數,以初始化在虛基類中定義的數據成員;
(2)注意在調用各構造函數時,最先調用虛基類的構造函數,再調用其他構造函數;
(3)虛基類的構造函數僅調用一次[5]。
盡管在課堂上講授了面向對象程序設計C++中虛機制的基本特征、功能作用等基本理論基礎知識,但要學生在短時間內很好理解、掌握并能實際應用,還必須經過編程訓練這一課外實踐環節,從而延伸、反轉課堂,以學生為主,逐步引導學生將其基本思想、理論和技術綜合應用到實際程序開發設計中。在此,通過一個案例設計來分析說明虛機制在面向對象程序設計中的綜合應用。
實例:將虛函數、虛析構函數和虛基類這三個虛機制對象綜合應用到一個實際的面向對象程序設計中。
程序代碼說明如下:
#include<iostream.h>
#include<string.h>
class Person{//定義基類
protected:char*name;
int age;
public:Person(char*nm,inta){
name=new char[strlen(nm)+1];
strcpy(name,nm);
age=a;
}
virtual~Person(){delete[]name;}//聲明基類的虛析構函數
virtual void show(){cout<<name<<""<<age<<"";} //聲明虛函數
};
class Student:virtual public Person{//聲明由虛基類派生
protected:char*number;
int score;
public:
Student(char*nm,int a,char*no,int sc):Person(nm,a){
number=new char[strlen(no)+1];
strcpy(number,no);
score=sc;
}
virtual~Student(){delete[]number;}//聲明派生類的虛析構函數
void show(){//虛函數重定義
Person::show();
cout<<number<<""<<score<<end l;
}
};
class Staff:virtual public Person{//聲明由虛基類派生
protected:char*idnumber;
floatwage;
public:
Staff(char*nm,inta,char*id,floatw):Person(nm,a){
idnumber=new char[strlen(id)+1];
strcpy(idnumber,id);
wage=w;
}
virtual~Staff(){delete[]idnumber;}//聲明派生的虛析構函數
void show(){//虛函數重定義
Person::show();
cout<<idnumber<<""<<wage<<endl;
}
};
class StaffStudent:public Staff,public Student{//多重繼承
public:
StaffStudent(char*nm,inta,char*id,floatw,char*no,int sc):
Staff(nm,a,id,w),Student(nm,a,no,sc),Person(nm,a){}
void show(){//虛函數重定義
Person::show();
cout<<idnumber<<""<<wage<<""<<number<<""<<score<<""<<endl;
}
};
voidmain(){
Person*p;
Student st("李剛",19,"20151301",560);
Staff sf("王艷",29,"010",3500.9);
StaffStudent ss("鄧軍",25,"014",4500.5,"20151306",580);
p=&st;
p->show();//實現多態
p=&sf;
p->show();
p=&ss;
p->show();
}
程序運行結果如圖5所示:

圖5 虛機制的綜合應用
綜上所述,虛機制貫穿著《面向對象程序設計C++》教學過程的始終,而虛機制特征主要通過虛函數、虛析構函數和虛基類等這三個虛機制對象來具體實現。因此,在實際的教學活動過程中,應該設計并使用靈活、恰當的教學手段和教學方法來完成這三個虛機制對象的具體教學任務,以利于指導學生更好地理解、掌握虛機制對象的基本功能特征及其應用,并有效激發學生的學習興趣,從而達到提高本課程教學質量、取得良好教學效果的目的。
[1]甘玲,邱勁.面向對象技術與Visual C++[M].北京:清華大學出版社,2006:4~7
[2]李師賢,李文軍,周曉聰,等.面向對象程序設計基礎(第二版)[M].北京:高等教育出版社,2011:316~318
[3]張冰.面向對象程序設計C++語言編程[M].北京:機械工業出版社,2008:154~155
[4]譚浩強.C++程序設計[M].北京:清華大學出版社,2004:407~408
[5]張海藩,牟永敏.面向對象程序設計實用教程(第二版)[M].北京:清華大學出版社,2007:165~167
Teaching Method;Object-Oriented Programming;VirtualMechanism
Research on the Method of VirtualMechanism in Object-Oriented Programm ing C++Course
WEIQing-qing,CUIRu-chun,LIYa
(School of Electronics and Information Engineering,Foshan University,Foshan 528000)
Virtualmechanism is the important study content in the Object-Oriented Programming C++course.Analyses the basic characteristics of virtualmechanism,and explores teaching emphasis,teaching difficulties,teachingmeans and teachingmethods of the virtualmechanism. Combiningwith the characteristics of the course learning,gives specific application examples to show the practical application of the virtualmechanism in object-oriented program design.Improves the teaching effectand completes the teaching task successfully.
1007-1423(2015)15-0021-06
10.3969/j.issn.1007-1423.2015.15.006
韋慶清(1966-),女,廣西河池人,碩士,講師,研究方向為計算機應用
崔如春(1965-),男,湖南沅江人,碩士,副教授,研究方向為計算機應用
李婭(1978-),女,湖北黃石河人,碩士,講師,研究方向為智能優化算法
2015-04-21
2015-05-06