复习笔记(二)——C++面向对象设计和使用
面向對象編程(OOP)
面向對象(Object Oriented )是認識事務的一種方法,是一種以對象為中心的思維方式
面向對象的程序設計:
對象=(算法+數據結構)
程序=對象+對象+……+對象
面向對象程序設計模擬自然界認識和處理事物的方法,將數據和對數據的操作方法放在一起,形成一個相對獨立的整體——對象(object),同類對象還可抽象出共性,形成類(class )。一個類中的數據通常只能通過本類提供的方法進行處理,這些方法成為該類與外部的接口。對象之間通過消息(message)進行通訊。
我們把對象之間產生相互作用所傳遞的信息稱做消息。
C++將“向對象發消息”處理成“調用對象的某個成員函數”
基本概念——對象
世界上所有的事物都可以稱為對象(Object)。對象可以是有形的如:一臺電視機等。也可以是無形的如:帳戶、一項記錄等。
一個對象就是一個獨立存在的客觀事物,它由一組屬性和對屬性進行操作的一組操作構成。
- 屬性是對象靜態特征的描述
- 操作是對象動態特征的描述
屬性和操作是對象的兩大要素。如電視的屬性有:品牌、尺寸、重量等。操作有:收視、選臺、音量調節等。
基本概念——類
類是一個抽象的概念,用來描述某一類對象所共有的、本質的屬性和類行為。
類實根據抽象的原則對客觀事物進行歸納和劃分。
面向對象的基本特征
- 抽象
- 封裝和數據隱藏(簡單介紹)
- 繼承
- 多態
封裝和數據隱藏
封裝是指按照信息屏蔽的原則,把對象的屬性和操作結合在一起,構成一個獨立的對象。
通過限制對屬性和操作的訪問權限,可以將屬性“隱藏”在對象內部,對外提供一定的接口,在對象之外只能通過接口對對象進行操作。
封裝性增加了對象的獨立性,從而保證了數據的可靠性。
外部對象不能直接操作對象的屬性,只能使用對象提供的服務。
抽象的設計思路
數據抽象化為屬性
處理過程抽象化為操作(方法)
-例如:當建立一個圖書管理系統時,通過直覺知道系統里一定要有圖書管理員/讀者/書這些對象, 而其中讀者的行為含有借書/還書,學生還有其相應的學號/姓名/班級等內容
類的定義
C++通過建立數據類型——類來支持封裝和數據隱藏。一個定義完好的類可以作為獨立模塊使用。
類的定義格式分為說明部分和實現部分
—說明部分包含數據成員和成員函數說明
—實現部分是用來對成員函數的定義
類的一般定義格式如下:
class <類名> {public :<公有數據成員和成員函數>;protected:<保護數據成員和成員函數>;private :<私有數據成員和成員函數>; };class是定義類的關鍵字是數據類型說明符,<類名>是一個標識符,用于唯一地標識一個類(新的數據類型),類名后面花括號擴起來的部分是類體(Class Body)。
類體中定義了類成員表(Class Member List)
—數據成員(Data Member)
—函數(Member Function)
public、protected和private是訪問限定符(access specifier)
一般在類體內先說明公有成員,它們是用戶所關心的,后說明私有成員,它們是用戶不感興趣的,但此順序并不是必須的。
***注意:
①在類的說明部分之后必須加分號“;”。
②類的定義放在一個頭文件中(.h),供其它需要使用該類的文件包含
③類的實現部分放在一個源文件中(.cpp),該文件需要包含定義類的頭文件
④類的定義和實現可以放在一個文件里,但不提倡,因為結構不清晰,影響了程序的可讀性
數據成員(屬性)
類中的數據成員的類型可以是任意的,可以定義各種類型的變量、指針、數組等,甚至是其他類的對象。
在說明數據成員時,一般按數據成員的類型大小,由小到大說明,這樣可提高空間利用率。
在類的定義中只能聲明數據成員,不允許對所定義的數據成員進行初始化。
類的數據成員只能在類里聲明,類的數據成員最好都是私有的
外部函數需要修改它,一般也只給它提供公有函數接口,讓它通過類的公有成員函數訪問類的私有數據數據成員也可以放在public部分,但不提倡
成員函數(方法)
成員函數可以直接使用類定義中的任一成員,可以處理數據成員,也可調用成員函數。
類的成員函數定義通常可采取兩種方式,即外部定義和內部定義(不推薦!影響到了程序的可讀性)。
成員函數的實現一般放在類的外面,在類里面對函數的原型進行聲明
成員函數的實現在類的定義外面時,必須聲明其所屬,在函數名前加類名和作用域運算符“::”,用來表示某個成員函數屬于哪個類的,定義格式如下:
返回類型 類名::成員函數名(參數說明) {函數體 }類成員函數的實現也可以放在類里,不需要加類名和作用域運算符
訪問控制
三個訪問說明符:public、private和protected
作用:控制對類的成員的訪問
在用class定義的類中,默認的訪問方式是private
在類的定義中,三個訪問說明符都可以使用多次(不提倡)。它們的作用域是從該說明符出現開始到下一個說明符之前或類體結束之前結束。
訪問符說明
private:類的私有成員只能被類的成員函數、友元函數、友元類訪問,類外無法訪問他們
protected:類的受保護成員能被類的成員函數、友元函數、友元類和派生類成員函數訪問
public:類的公有成員可以被類的成員函數、友元函數、友元類所有能訪問到類的對象的外部程序代碼直接訪問,這部分往往是一些操作(即成員函數)
類的公有成員是類的對外接口
類的功能
類定義了函數(方法)和數據(屬性)的訪問控制屬性
—哪些成員可被外界直接訪問
—哪些成員只能被自己的成員函數訪問
封裝和信息隱藏技術使類變得很安全
私有數據成員只有類自己的成員函數能訪問
只要確保成員函數操作的合理合法性,對象就是安全的
提高了程序的可維護性
對象的定義
對象是類的實例。對象是屬于某個已知的類。
定義對象之前,一定要先定義好該對象的類。
定義好的類可以作為新的數據類型來使用
聲明的語法:類的名稱 對象的名稱;
例如:
構造函數
對于對象的初始化,采用構造函數(constructor)。編寫一個或一組構造函數。構造函數是特殊的成員函數
構造函數的功能:為對象分配空間;對數據成員賦初值;請求其他資源。
如何聲明構造函數:
—函數名和類名完全相同
—不能定義構造函數的類型(返回類型),也不能使用void
—構造函數應聲明為公有函數,但它不能像其他成員函數那樣被顯式地調用
—構造函數可以有任意類型和任意個數的參數,一個類可以有多個構造函數(重載)
創建類的對象時,自動調用類的構造函數
創建一個對象時只調用一個構造函數(根據參數列表)且只在創建時調用一次
構造函數的種類
普通構造函數:有兩個或兩個以上參數的構造函數
默認構造函數
復制(拷貝)構造函數
類型轉換構造函數
重載構造函數
在一個類需要接受不同的初始化值時,就需要編寫多個構造函數, 他們之間構成重載關系。
示例:
class Student{ private:char m_No[4],m_Name[21];int m_Age,m_Score[5]; public:Student(); //默認構造函數Student(char *name,int age,int score[5]); //重載構造函數 };默認構造函數
-
哪種構造函數是默認構造函數?
沒有參數或者所有的參數都有默認值的構造函數。
-
類里一定會有默認構造函數嗎?
如果類中沒有聲明構造函數,編譯器將自動產生一個公共的默認無參數構造函數;如果存在一個構造函數聲明,那么編譯器不會產生一個默認的構造函數
-
默認構造函數何時調用?
沒有指明初始化對象時,便按默認構造函數來初始化該對象。
例如:Person p1,p2; //使用默認構造函數對p1和p2進行初始化 -
一個類中只能有一個默認構造函數
(如果一個構造函數的所有參數均有默認值,這時再定義無參數的默認構造函數無意義,會產生調用時二義性)
構造函數中使用默認參數
可以為類的成員函數指定參數的默認值,包括構造函數在內。
要把默認參數值放在函數聲明中,而不應放在函數定義中
如果一個構造函數的所有參數均有默認值,這時再定義無參數的默認構造函數無意義,將產生調用時二義性。
示例:
class CCube{ public:CCube(double len);CCube(int len=12);//CCube(); private:double m_len; }; CCube::CCube(int len){m_len=len;}拷貝(復制)構造函數
特殊的構造函數
功能:使用一個已經存在的對象來初始化一個新的本類的對象
聲明:只有一個參數并且參數為該類對象的引用
class 類名{public: 類名(類名 &對象名);};如果類中沒有說明復制構造函數,則系統自動生成一個缺省復制構造函數,作為該類的公有成員。
淺復制和深復制
淺復制:將對象數據成員的值進行簡單的復制
深復制:不僅將對象數據成員的值進行復制,而且對指針型數據成員生成新空間,然后復制對應的值
實例:
#include <string.h> #include <iostream.h> class Employee { public:Employee(char *n);Employee(Employee &emp);~Employee(); public:char *name; }; Employee::~Employee() {//析構函數delete [] name; } Employee::Employee(char *n) {name = new char[strlen(n)+1];strcpy(name,n); } Employee::Employee(Employee &emp) {int len=strlen(emp.name);name=new char[len+1];strcpy(name,emp.name); } int main() {Employee emp1("zhang");Employee emp2(emp1);//Employee emp2=emp1;cout<<"emp2.name = "<<emp2.name<<endl;return 0; }**注意:對象中包含動態分配的數據成員時,復制構造函數的實現不能只是簡單的賦值。應該先為當前對象的數據成員分配新的空間,再將參數對象中相應的數據復制過來。
拷貝構造函數的其他作用
當函數的形參是類的對象,調用函數時,進行形參與實參結合時使用。這時要在內存新建立一個局部對象,并把實參拷貝到新的對象中。理所當然也調用拷貝構造函數。
當函數的返回值是類對象,函數執行完成返回調用者時使用。理由也是要建立一個臨時對象中,再返回調用者。為什么不直接用要返回的局部對象呢?因為局部對象在離開建立它的函數時就消亡了,不可能在返回調用函數后繼續生存,所以在處理這種情況時,編譯系統會在調用函數的表達式中創建一個無名臨時對象,該臨時對象的生存周期只在函數調用處的表達式中。所謂return 對象,實際上是調用拷貝構造函數把該對象的值拷入臨時對象。如果返回的是變量,處理過程類似,只是不調用構造函數。
轉換構造函數
提供了單個參數的構造函數
相當于將一個其他類型的數值或變量轉換為自身類型的數據。
類的構造函數只有一個參數是非常危險的,因為編譯器可以使用這種構造函數把參數的類型隱式轉換為類類型
實例:
#include <string.h> #include <iostream.h> class CCube { public:CCube(double len){m_len=len;} public:double m_len; }; int main() {CCube cube=12.4;cube=11; //隱式轉換cout<<"cube.m_len = "<<cube.m_len<<endl;return 0; }執行結果: cube.m_len = 11explicit關鍵字
只提供給類的構造函數使用的關鍵字。
編譯器不會把聲明為explicit的構造函數用于隱式轉換,它只能在程序代碼中顯示創建對象
#include <string.h> #include <iostream.h> class CCube { public:explicit CCube(double len){m_len=len;} private:double m_len; }; int main() {CCube cube = 12.4;//不允許//cube=11;//不允許return 0; }析構函數
特殊的成員函數
作用:撤銷對象前做清理工作,一般是釋放對象在生存期間動態申請的空間
當對象超出其定義范圍時(即釋放該對象時),編譯器自動調用析構函數。
-對象被定義在函數體內,則當這個函數結束時,該對象的析構函數被自動調用。
-對象是使用new運算符動態創建的,在使用delete運算符釋放它時,delete將會自動調用析構函數
函數名和類名相似(前面多了一個字符“~”)
注意:析構函數沒有返回類型,沒有參數,析構函數不能被重載
如果沒有定義析構函數,編譯器會自動生成一個默認析構函數,其格式如下:
類名::~默認析構函數名( ) { }默認析構函數是一個空函數。
示例:
class Student { public:Student();~Student(); private:char *m_name; }; Student :: Student() {cout<<"Default constructor called"<<endl;m_name=new char[5];strcpy(m_name,"abc"); } Student ::~Student() {cout<<"Free"<<endl;delete []char; } 《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的复习笔记(二)——C++面向对象设计和使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python学习笔记(五)——函数基础和
- 下一篇: 复习笔记(三)——C++类和对象