◆沈 煒 莊巧莉
(浙江理工大學信息電子學院)
基于內部視角的C++面向對象教學實踐
◆沈 煒 莊巧莉
(浙江理工大學信息電子學院)
面向對象程序設計是計算機專業學生的重要基礎課,絕大多數高等院校都以 C++作為面向對象程序設計這門課程的教學語言。應該看到,面向對象技術的實現是有著嚴密的技術體系結構的,教學的過程,也是這一體系結構向學生逐步展示,讓學生逐步理解并掌握的過程。但在具體的教學過程中,卻有著很多的概念和方法,十分難以理解和掌握。其中,有些內容,甚至連教科書都出現自相矛盾的情況。如何采用更為有效的教學方法,避免出現類似的情況,實現良好的教學效果,是一個需要重點關注的問題。另一方面,計算機語言類課程,作為計算機專業課程最基礎的課程,在教學中,由于開課一般先于其他專業課程,很難將其他專業課程的內容與當前課程內容相結合,容易陷入為教語言而教語言的境地。因此,采用何種方式,既能讓學生容易理解語言中的難點,又能突破語言教學本身的限制,這是計算機語言類課程教學所面臨的一個重大問題。
在教學準備過程中,我們對 C++語言的難點進行了深入地分析,發現這些內容往往都有這樣的特點,即單純從 C++語言本身,很難甚至無法詮釋其技術原理,因此不引入新的知識,就無法讓學生了解這些技術的實現原理,做到不僅“知其然”,而且“知其所以然”。因此,在教學過程中,我們提出采用基于內部視角的教學方法,在相關知識的教學過程中,引入了計算機內部實現的技術細節,在并不增加學生知識量的同時,通過說明技術的實現過程,使學生了解相關的技術原理,從而在掌握相關概念和方法的同時,加深對面向對象技術的了解和認識,突破語言教學本身所受的限制,為其他的相關專業課的學習打下較好的基礎。
所謂基于內部視角的教學方法,是在計算機程序設計語言的教學過程中,適當地引入包括匯編、編譯、鏈接、調試和運行等相關技術實現的內容,從而使學生能夠對一個程序從編輯到編譯,乃至運行等各個環節中,計算機內部組織結構和運行過程的方法,有一個正確的認識。
顯然,該方法對培養一名專業的程序員是十分有益的,這方面的內容,也是一名專業程序員所必須具備的。但該教學方法在使用上還有著很大的不確定性,主要包括:
(1)程序設計語言本身的限制。由于不同的程序設計語言在計算機體系中所處的層次不同,因此,這一方法的實施有著本質的不同。例如,象VB.Net、C#等語言,由于建立在.Net框架基礎之上,技術實現細節復雜,因此較難采用此方法;而對于匯編語言來說,內存組織等相關技術內容,則是實踐教學中的重要內容。對于象 C和 C++這樣的中間語言來說,如何把握,則要根據教學內容進行取舍;
(2)引入程度的把握。計算機內部實現的技術細節有著先天的難度,實施中必須考慮學生的知識水平和結構,把握引入的程度。
我們認為,基于內部視角的教學方法在以 C++為編程語言的面向對象程序設計教學中,應該在如下方面引入:
(1)單純以 C++語言無法完美解釋的相關概念、技術等;
(2)作為學生選學的提高內容;
(3)實踐教學環節的組成和補充。
在引入的內容方面,應遵循以下原則:引入的內容對學生目前的認知水平和知識結構來說,不會存在困難。
我們以若干實例來說明基于內部視角的教學方法的應用。
實例 1:繼承類與基類構造函數的調用順序
在這一內容方面,教材[1]認為,派生類對象的構造函數調用順序是:基類構造函數先調用,派生類函數后調用。并用如下程序的輸出來佐證。
//功能:演示繼承關系中基類與派生類的構造函數與析構函數的調用次序。

類似的程序也出現在文獻[2]和[3]中,而文獻[2]和文獻[3]也持同樣的觀點。但我們認為,這與構造函數的調用原理是矛盾的,至少是不嚴謹的。問題在于:一個類的對象成員在初始化時,要調用該類的構造函數,而派生類對象作為該派生類的對象,在初始化時,怎么會先調用非該派生類的構造函數呢?而且,這與繼承類的構造函數的定義也相違背,因為基類構造函數的參數是由繼承類的構造函數傳遞而來的,若是基類的構造函數先被調用,則所使用的參數從何而來?但單純地如此說明,沒有實驗的佐證,不能給學生以深刻的印象。
在教學中,我們演示了應用Visual Studio 6的代碼跟蹤過程,來讓學生充分地了解這一點。在跟蹤過程中,打開匯編代碼的顯示開關,在0x40109D處,清晰地看到繼承類的構造函數被調用了,如圖 1所示,而在繼承類構造函數調用過程中,基類的構造函數被調用。

圖 1 構造函數調用順序 (圖中黑行分別表示調用派生類和基類構造函數)
這樣,學生在觀察的基礎上能夠得到關于基類、派生類構造函數正確的調用順序。進一步跟蹤還能夠發現,雖然派生類對象構造函數調用順序是先派生類再基類,但數據成員的初始化卻是按先基類再派生類的順序進行。因此,這一知識點可以用兩句話概括:派生類對象構造函數調用順序是先派生類后基類,而數據成員初始化則是先基類成員后派生類成員。在明確了整個過程之后,學生可以認識到,單純依據 cout的輸出來判斷構造函數的調用順序是不可靠的。
采用同樣的方法,學生同樣能夠理解,C++程序中,代碼可以先于main函數執行這一知識點。在這部分內容的教學中,學生直觀地感受到語言代碼在計算機內部的執行過程,同時,對程序的調試又有了新的認識和方法。
實例2:虛函數的調用
虛函數是一塊較為難以理解的內容,很多學生說到虛函數就說心里“發虛”,原因是用 C++語言本身的知識,很難解釋為什么指向基類對象的指針在指向派生類對象時,調用虛函數會進行動態綁定,而用對象直接調用虛函數卻不存在這一情況,這一現象與前面指向對象的指針的知識有著很大的不同。僅按書本的內容,勢必只能讓學生了解這一現象,而不能讓學生真正了解多態性這一能體現OOP思想的典型現象中包含的實現方法,這對建立和培養基于 OOP對現實世界的實體進行抽象的思想是不利的。
在這一節,我們在教學過程中,引入了虛函數表的知識,講明如果一個類有虛函數,那么會在類中產生一個虛函數表,基類和派生類的同名虛函數在這個表中的位置是相同的,在調用虛函數時,程序是先查找這個虛函數表,然后根據表中的地址調用對應的虛函數。當指針指向基類對象或指向派生類對象時,所使用的虛函數表是不同的,這樣,指針與虛函數表結合,從而實現了動態綁定這一運行時的多態性。在講授中,我們只引入了虛函數表,但對虛函數表在內存中的位置,組織等則略過,這樣既讓學生掌握了原理,又不會因為繁瑣的細節而失去對整體知識的把握,從而影響教學效果。
在課后,我們對3個班的面向對象課程作了問卷調查,問卷的設計圍繞著基于內部視角的教學方法展開。問卷發放 103份,總計收到有效問卷95份。在這些有效問卷中,有70.59%的學生認為,面向對象這門課在認識上存在著困難;有 39.2%的學生認為,困難的原因是內容本身的難度,有51%的學生認為,內容的難度是由“可以知其然,而難以知其所以然”造成的。從這個結果來看,引入適當的內容,使得有難度的知識點得到合理的詮釋顯然是必要的,顯然,基于內部視角的教學方法正切合了這一實際。調查情況也證實了這一點,有 88.02%的學生認為,引入內部實現機制內容對本門課程有很大的幫助,同時,還有 82.44%的學生認為,這樣的知識結構對今后的職業生涯也有很大的幫助。
從上述調查結果可以看出,基于內部視角的教學方法較為符合目前學生在面向對象程序設計這門課中的認知情況,符合學生在專業課中“想知其然并知其所以然”的認識能動性,并在較大程度上幫助學生更好地理解課程的內容,同時,也開拓了學生的視野,能夠達到較為良好的教學效果。
本文提出了一種在面向對象程序設計教學中的基于內部視角的教學方法,該方法主旨是在面向對象課程教學中,適當引入計算機內部實現的內容,從而能夠使學生了解面向對象語言本身所難以詮釋的內容,不僅讓學生能夠掌握相關課程內容,還能夠了解相關技術實現機制,擴展了語言教學視野,從教學調查和實踐來看,起到了比較好的教學效果。
應該看到,由于C++語言是基于中級語言C發展起來的,應用內部視角教學方法具有一定的優勢,對于 java、C#等高級面向對象語言,如何恰當地應用該方法,則需要在今后的教學過程中加以探索。
[1]李師賢.面向對象程序設計基礎.高等教育出版社,2005.
[2]Stephen Prata.C++Primer Plus Fifth Edition.Macmillan Computer Pub,2005.
[3]Bruce Eckel.Thinking in C++ Second Edition.機械工業出版社,2002.
浙江理工大學重點課程建設項目(ZDKC0908)。