ylbtech-專業詞匯-計算機-面向對象技術-OOP:類 |
類(Class)是面向對象程序設計(OOP,Object-Oriented Programming)實現信息封裝的基礎。類是一種用戶定義類型,也稱類類型。每個類包含數據說明和一組操作數據或傳遞消息的函數。類的實例稱為對象。
1.返回頂部 |
1、
2、
2.返回頂部 |
1、
介紹
類的實質是一種數據類型,類似於
int、char等基本類型,
不同的是它是一種復雜的數據類型。
因為它的本質是類型,而不是數據,所以不存在於內存中,不能被直接操作,只有被實例化為對象時,才會變得可操作。
類是對現實生活中一類具有共同特征的事物的抽象。如果
一個程序里提供的類型與應用中的概念有直接的對應,這個程序就會更容易理解,也更容易修改。一組經過很好選擇的用戶定義的類會使程序更簡潔。此外,它還能使各種形式的代碼分析更容易進行。特別地,它還會使
編譯器有可能檢查對象的非法使用。
類的內部
封裝了方法,用於操作自身的成員。
類是對某種對象的定義,具有行為(be-havior),它描述一個對象能夠做什么以及做的方法(method),它們是可以對這個對象進行操作的程序和過程。它包含有關對象行為方式的信息,包括它的
名稱、方法、屬性和事件。
類的構成包括
數據成員和成員函數。數據成員對應類的屬性,類的數據成員也是一種數據類型,並不需要分配內存。成員函數則用於操作類的各項屬性,是一個類具有的特有的操作,比如“學生”可以“上課”,而“水果”則不能。類和外界發生交互的操作稱為
接口。
用法
定義一個類
class 類名 { public: 公有成員 private: 私有成員 protected: 保護成員 };
-
結尾部分的分號必不可少,否則會發生語法錯誤。
-
無論公有成員、私有成員還是保護成員,彼此之間都可以訪問。比如公有的成員函數可以操作保護的數據成員,也可以調用私有的成員函數。
-
類的數據成員是類型,所以不能被賦值,聲明數據成員和聲明普通變量的格式相同,比如“int n;”。
成員函數的實現
構造函數與析構函數
-
函數名固定構造函數和析構函數的 函數名必須是類名。
-
聲明格式不同構造函數的聲明形式:類名(參數列表);析構函數的聲明形式:~類名();
-
重載的特殊性構造函數和普通成員函數一樣可以被重載, 析構函數不可以重載,只能是空參數。
-
調用過程不同
即使顯式地定義構造函數和析構函數,也還是會有默認的構造函數和析構函數,函數內部無任何語句,不執行任何操作。
默認構造函數是無參數的。需要注意的是,
一旦顯式定義任意形參的構造函數,默認構造函數都不會生成,即只有沒有定義構造函數的類才存在默認構造函數。
一般情況下,默認的構造函數和析構函數可以滿足功能需要,然而當需要
重載構造函數,或是需要動態分配資源的時候,就不得不定義自己的構造函數甚至析構函數了。
類的實例化
就像聲明某種類型的變量一樣,聲明一個類類型的對象,就是類的實例化,會涉及到必要的內存分配。
不同語言中類的實例化形式是不同的。
-
類名 對象名(參數列表);
-
Java/C#類名 對象名 = new 類名(參數列表);括號不能省略。
-
類的公有成員 可以被該類,其派生類和類實例化的對象訪問。
-
類的保護成員 可以被該類及其派生類訪問,不可以被該類的對象訪問。
-
類的私有成員 可以被該類訪問,不可以被派生類及其該類的對象訪問。
派生與繼承
class 子類類名: public 父類類名,private 父類類名, protected 父類類名 { public: 公有成員 private: 私有成員 protected: 保護成員 };
派生和繼承是類的重要特性,
繼承是由抽象到具體的體現。
通過繼承,子類可以使用父類的成員。
但要注意的是,
派生和繼承在帶來方便的同時,也會使類與類之間的關系變得復雜,尤其是涉及到私有繼承和保護繼承時,類中成員的關系可能會變得難以理解。
所以在涉及類時,盡量避免過多層次的繼承,私有繼承和保護繼承的使用也要慎重。
繼承來的成員和自身聲明的成員並無本質區別,也有公有成員、私有成員、保護成員之分。繼承時,父類中成員類型(公有成員/私有成員/保護成員)和繼承方式(公有繼承/
私有繼承/保護繼承)不同,情況不同。可以歸納為:
三種類型的繼承,父類的成員均被子類繼承(之前的百科關於這點的描述是錯誤的),只是由類實例化的對象對其繼承的成員的訪問權限會有所變化。三種不同方式的繼承,描述的是子類實例化對象對其成員的訪問權限,並非是描述子類時,子類對繼承自父類的成員的訪問權限。
-
公有繼承繼承自父類的成員保持不變。
-
私有繼承繼承自父類的成員全部變為私有成員。
-
保護繼承繼承自父類的公有成員變為保護成員,其余不變。
操作符重載
操作符重載必須在類中進行,
重載
操作符可以使操作符對在類中的語義發生變化。除了. ,.* ,:: ,? : 、sizeof、
typeid這幾個運算符不能重載之外,大部分運算符都能被重載。但要注意,重載操作符並不能改變操作符的優先級和
結合律,而且從認知規律上講,重載的操作符功能必須與原意相近,否則很難被人理解。
操作符重載是函數,在使用該操作符時被調用。操作符重載函數的聲明形式:
返回值 operator操作符(參數列表);
友元
通常,類中的私有成員只能被自身使用,無法被它的對象訪問。因此,另一個類即便可以使用該類的對象,也無法訪問該類的私有成員,通過定義友元的方法可以做到這一點。
友元就是在一個類中“再次聲明”另一個類的成員函數或是另一個類,被“再次聲明”的成員函數或類可以訪問該類的私有成員。這種“再次聲明”並不是普通的聲明,格式為:
friend 函數/類名;
顯然,友元會破壞類的封裝性,使本該隱藏的成員暴露出來,因此應當謹慎使用。
組合
繼承可以描述“交通工具”和“公交車”的關系,卻無法描述“公交車”和“車輪”的關系。
-
大多數“車輪”具有的特性是“公交車”所不具有的。比如說“車輪”具有“重量”,而“公交車”的“重量”則是另一個含義。而通過私有成員、保護成員機制控制這些成員的繼承性,會使繼承變得復雜而難以理解。而且
-
繼承來的數據成員只有一個,而一輛“公交車”卻有四個“車輪”,四個“車輪”的“重量”。
引入組合的概念,“公交車”完全可以由“車輪”、“方向盤”、“車身”等類組合而來。
方法就是將類當成其他的數據類型一樣,在另一個類中定義該類類型的數據成員。
抽象類
並不是所有種類的事物都可以被實例化,換而言之,有的種類只是一種抽象概念,現實中並沒有實際存在的對應物。比如:假設所有的動物都會叫,我們可以定義一個類——“動物”,定義類中的一個成員函數——“叫”,我們知道貓的叫聲,也知道狗的叫聲,然而“動物”是如何“叫”的?——我們根本無法實現它。所以,我們引入了
抽象類的概念,
抽象類是無法被實例化的,無法聲明抽象類的對象。
抽象類只能被用作
基類,作用體現在:
靜態成員
特性
類的三大特性
-
封裝性
-
繼承性 更符合認知規律,使程序更易於理解,同時節省不必要的重復代碼。
與結構體的區別
在
C++、C#語言中,class和struct都可以定義一個類,它們的區別如下:
-
從職能觀點來看, class表現為行為;而struct常用於存儲數據。
-
class的對象復制分為淺拷貝和深拷貝,必須經過特別的方法來完成復制;而struct創建的對象復制簡單,可以直接以等號連接即可。
-
class實例由垃圾回收機制來保證內存的回收處理;而struct變量使用完后立即自動解除內存分配。
-
作為參數傳遞時,class變量是以按址方式傳遞;而struct變量是以按值方式傳遞的。
我們可以簡單的理解,
class是一個可以動的機器,有行為,有多態,有繼承;而struct就是個零件箱,組合了不同結構的零件。其實,
class和struct最本質的區別就在於class是引用類型,內存分配於托管堆;而struct是值類型,內存分配於線程的堆棧上。由此差異,導致了上述所有的不同點。所以只有深刻的理解內存分配的相關內容,才能更好的駕馭。
當然,使用class基本可以替代struct的任何場合,class后來居上。雖然在某些方面struct有性能方面的優勢,但是在面向對象編程里,基本是class橫行的天下。
那么,有人不免會提出,既然class幾乎可以完全替代struct來實現所有的功能,那么struct還有存在的必要嗎?答案是,
至少在以下情況下,鑒於性能上的考慮,我們應該考慮使用struct來代替class:
示例
類的復用
class Animal { private void beat() { System.out.println(""); } publicv oid breath() { beat(); System.out.println("") } } class Bird { // private Animal a; public Bird(Animal a) { this.a=a; } // pubilc void breath() { // a.breath(); } public void fly() { System.out.println("") } } class Wolf { // private Animal a; }
2、
3.返回頂部 |
4.返回頂部 |
5.返回頂部 |
1、
2、
6.返回頂部 |
![]() |
作者:ylbtech 出處:http://ylbtech.cnblogs.com/ 本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。 |