徐曉蓉+李永軍
摘要:類和對象是面向?qū)ο蟪绦蛟O(shè)計中非常重要的概念,也是初學(xué)者不容易理解的概念之一,該文用類比的方法清楚地解釋了類和對象的概念,并在內(nèi)存層面對類和對象進行了深入的剖析,使學(xué)生能更加清晰地理解什么是類,什么是對象,以及類和對象在內(nèi)存中的存儲形式。
關(guān)鍵詞:類和對象;數(shù)據(jù)和操作;方法;屬性和行為
中圖分類號:TP312 文獻標(biāo)識碼:A 文章編號:1009-3044(2017)35-0106-03
A Thorough Analysis of Class and Object in C ++ by Analogy
XU Xiao-rong1, LI Yong-jun2
(1.College of Computer Science and Technology, Hunan University of Arts and Science, Changde 415000, China;2.School of Physics and Electronics, Henan University, Kaifeng 475004, China)
Abstract: Class and object are very important concepts in the Object-Oriented Programming, and they are very difficult to be understood by the beginners. In this paper, the concepts of class and object are explained clearly by analogy, and class and object are analyzed in memory, so that students can more easily understand what the class is , what the object is, and how class and object are stored in memory.
Key words:classes and objects; data and operation;methods; properties and behaviors
1 背景
類和對象是C++等面向?qū)ο蟪绦蛟O(shè)計中最重要的兩個基本概念,但就作者多年教授這門課的經(jīng)驗看,學(xué)生大多因為有面向過程程序設(shè)計的基礎(chǔ),最初都很難清楚地理解面向?qū)ο蟪绦蛟O(shè)計中的類和對象這兩個概念,從而碰到問題總是很容易想到面向過程而很難想到使用面向?qū)ο蟮姆椒▉斫鉀Q問題。本文通過類比法,對類和對象的定義進行了對比、分析和解釋,并在內(nèi)存層面深入剖析了類和對象在內(nèi)存中的存在形式,有助于初學(xué)者更快、更準(zhǔn)確的理解類和對象的概念。
2 用類比法理解類和對象的定義
2.1 類的定義
數(shù)學(xué)上,所謂定義,即是對于一種事物的本質(zhì)特征的確切而簡要的說明;比如,質(zhì)數(shù)的定義:除了1和它本身以外不再有其他因數(shù)的大于1的自然數(shù)。
而在C++中,類的定義也是先找出類的特征,再給出類定義的描述,即必須首先對某類的若干對象進行分析,總結(jié)出該類對象(所關(guān)注)靜態(tài)的屬性(或數(shù)據(jù))和動態(tài)的方法(或行為、或操作),即特征,最后再使用關(guān)鍵詞class將所有屬性和方法整合起來來形成類的定義。
比如:通過對很多個人特征的分析發(fā)現(xiàn),對于人,通常關(guān)注的是姓名,性別,年齡等這些靜態(tài)的屬性,除此之外,人還有一些動態(tài)的行為,比如會思考、會說話、會微笑等等。當(dāng)總結(jié)出了人的靜態(tài)和動態(tài)的特征之后,就可以定義什么是人!用 c++語言來描述出來就是如下程序段:
[例程1]
class Person
{private:
char name[20];
int age;
char sex;
public:
void think()
{ cout << "I am a person, and I can think!"< } void talk() { cout << "I am a person, and I can talk with you!" << endl; } void smile() { cout << "I am a person, and I like smiling!" << endl; } }; [例程1]中,class是C++中用來定義類的關(guān)鍵詞,而Person是定義的類的名字,類名可以由程序員自己定義。從[例程1]中可以看出,C++中動態(tài)行為是用函數(shù)來表達的,稱為成員函數(shù),每一個成員函數(shù)都可以作為人與外界溝通交流的一個接口,所以,一般將成員函數(shù)定義成公有的(即public:)。而靜態(tài)的屬性,稱為數(shù)據(jù)成員,是用類型及屬性名來表示,一般是每個人所特有的,因此,一般將其定義為私有的(即private:)。當(dāng)然,每個類中有幾個成員函數(shù)以及它們的類型、參數(shù)及具體實現(xiàn)的功能需要程序員自己去按實際需要來定義與實現(xiàn),數(shù)據(jù)成員有幾個以及其名字、類型也是如此。 2.2 對象的定義 定義了類,相當(dāng)于定義了一種新的數(shù)據(jù)類型,與系統(tǒng)的基本數(shù)據(jù)類型相似。也就是說,在[例程1]中定義Person類之后,就可以像以前使用的int、double、float等一樣來使用Person了,只不過,用系統(tǒng)的基本數(shù)據(jù)類型定義的變量,通常稱為變量,而用用戶自己定義的類型如Person定義的變量,通常稱之為對象而已,如:
int a; //a是變量,a中可以存放一個int型的數(shù)據(jù)。
Person p; //而p,則是對象,p中可以存放一個Person型的數(shù)據(jù)。
對象的定義格式為:類型 對象名;
2.3 類和對象的使用
類是抽象的,而對象則是具體的。類和對象的關(guān)系就好比人和某人張三的關(guān)系,人只是存在于我們的意念中,而張三這個人卻是實實在在存在與這個現(xiàn)實世界中的。張三具有人的所有屬性和行為。[例程1]中的Person類就是抽象的,要想使用Person類,必須定義Person類的對象,通過具體對象來使用類。如Person p; 定義了具體對象之后,就可以通過給對象發(fā)送指令來使用類,如p.smile();等。
3 類和對象的內(nèi)存
3.1 類的內(nèi)存
類是抽象的,因此,類的定義只是一種定義性說明,類定義中的數(shù)據(jù)成員本身是不占內(nèi)存空間的,也就是說,類的內(nèi)存空間僅僅是定義類的那段代碼所占據(jù)的內(nèi)存空間。
3.2 對象的內(nèi)存
對象是具體的,具有類的所有屬性和行為。所以,理論上來說,對對象而言,它的屬性和行為都要占據(jù)內(nèi)存空間。
1) 普通類對象的內(nèi)存
定義Person類對象,Person p1,p2;那么,p1和p2對象的內(nèi)存示意圖如下圖1,圖2:
很顯然,對于同一個類的對象,每個對象中都有相同的成員函數(shù),這將造成內(nèi)存資源的極大浪費,因此,系統(tǒng)是將這些成員函數(shù)專門存儲在一個地方,每個對象的內(nèi)存中只存儲相應(yīng)的屬性,p1、p2的內(nèi)存狀態(tài)如圖3所示。從圖3中可以看出,每個對象在內(nèi)存中存儲的時候,只存儲屬于對象自己的數(shù)據(jù)成員,而沒有成員函數(shù)。對于不同對象如何使用存儲在同一個地方的相同成員函數(shù)在介紹this指針時再做解釋。
2) 派生類對象的內(nèi)存
[例程2]在上面[例程1]的Person類的基礎(chǔ)上派生出如下的Student類。
class Student :public Person
{
int num;
char major[30];
public:
void printMessage()
{cout <<"num:"< }}; 從理論上講,派生類具有基類的所有屬性和行為。如果有Student s; s對象的內(nèi)存狀態(tài)如圖4所示。由圖4可知,派生類對象的屬性具有兩類:基類的所有屬性、自己新增的屬性。但需注意,基類的屬性在派生類中是以無名對象(內(nèi)嵌對象用橢圓表示,以下類同。)的形式存在的, 所以,s對象的內(nèi)存示意如圖5所示。 3) 含虛基類的派生類對象的內(nèi)存 當(dāng)派生類的兩個基類有共同基類時,在派生類對象中就會有兩個共同基類的對象,如[例程3]中的Derive類的對象。 [例程3] class Base { int b; public: Base(int x=0) { b=x; cout<<"&b="<<&b< } }; class Base1: public Base { int b1; public: Base1(int x=0,int y=0):Base(x) { b1=y; } }; class Base2: public Base { int b2; public: Base2(int x=0,int y=0):Base(x) { b2=y; } }; class Derive:public Base1,public Base2 { int c; public: Derive(int x,int y,int z): Base1(100,y),Base2(200,z) { c=z; } }; void main() { Derive d(3,2,1); } 這時,在主函數(shù)中用Derive d(3,2,1)定義d對象之后,d的內(nèi)存狀態(tài)如圖6所示。很顯然,對象d中有兩個共同基類Base類的對象,這樣,會造成二義性。由于在Base類的構(gòu)造函數(shù)中加入了輸出b成員的地址,通過執(zhí)行程序,由圖7可以很明顯的看到,輸出了兩次b的地址,說明,在d對象中,有兩個不同的Base類的對象。 為了消除這種二義性,c++中引入了虛基類,如[例程4]所示。 [例程4]該程序是在[例程3]的基礎(chǔ)上僅僅加了2個virtual和一個Base(300) class Base { int b; public: Base(int x=0) { b=x; cout<<"&b="<<&b< } }; class Base1: virtual public Base { int b1; public: Base1(int x=0,int y=0):Base(x)
{ b1=y; }
};
class Base2: virtual public Base
{
int b2;
public:
Base2(int x=0,int y=0):Base(x)
{ b2=y; }
};
class Derive:public Base1,public Base2
{
int c;
public:
Derive(int x,int y,int z): Base(300),Base1(100,y),Base2(200,z)
{ c=z; }
};
void main()
{
Derive d(3,2,1);
}
d對象的內(nèi)存狀態(tài)如圖9所示,雖然,從內(nèi)存看好似還是有兩個共同基類Base類的對象,但此時,這兩個對象的b的值已經(jīng)是相同的,且是派生類Derive的構(gòu)造函數(shù)提供的值,而且程序執(zhí)行結(jié)果只輸出一個b的地址,如圖10所示。這說明,此時,在d對象中,已經(jīng)只有一個共同基類Base類的對象了,從而消除了二義性,由此,我們也可以得到d對象的內(nèi)存示意圖,如圖11所示。
4 結(jié)束語
初學(xué)者往往對類和對象的概念理解起來很不容易,本文通過類比法對類和對象的概念進行了分析解釋,并從內(nèi)存層面對類和對象進行了深入的剖析,讓學(xué)生可以從概念到本質(zhì)更好的理解類和對象的概念,通過實際教學(xué)和對學(xué)生的調(diào)查表明,通過此學(xué)習(xí),學(xué)生確實可以更深一層的理解類和對象的概念。
參考文獻:
[1] 洪陽. C++中學(xué)習(xí)類的設(shè)計方法和途徑的探究[J]. 寶鋼科技, 2014,40(1):60-63.
[2] 陳維興, 林小茶. C++面向?qū)ο蟪绦蛟O(shè)計教程[M].北京: 清華大學(xué)出版社, 2009.
[3] 譚浩強. C++程序設(shè)計[M]. 3版.北京: 清華大學(xué)出版社, 2015.
[4] 本賈尼·斯特勞斯特魯普. C++程序設(shè)計:原理與實踐(基礎(chǔ)篇)[M]. 2版.北京: 機械工業(yè)出版社, 2017.