文章目錄
-
- 第25講:類的定義
- 第26講:對象的定義和使用
- 第27講:構造函數
- 第28講:預設構造函數和指派構造函數
- 第29講:析構函數
第25講:類的定義
- C語言——面向過程的程式設計思想(自頂向下逐漸求精;一個main函數外加若幹子函數),C++——面向對象的程式設計思想(實作軟體設計的産業化;自然界是由實體對象構成的)。
- 【抽象】:資料抽象、行為抽象。
- 【封裝】:将抽象出的資料成員和行為成員聚合并視為一個整體——類(細節隐藏,接口開放)。
- 【繼承與派生】:保持類原有特性的基礎上,進行更具體的說明。
- 【類定義】:
class 類名{成員清單};
- 類可以沒有成員,也可以有多個成員;類的成員可以是資料,也可以是函數;類的定義一旦完成後就無法再添加成員了。
- 類中成員函數的聲明是必需的,但定義可在類外聲明。
- 類成員的通路有兩種來源:類成員和類使用者。
- 類成員具有通路控制屬性,分三種:
,public
,private
。protected
屬性将類成員開放給類外部的使用者通路(外部接口);public
屬性将類成員限制為僅給類内成員可通路;private
屬性将類成員限制為僅給類内成員可通路,此外該類的派生類的成員亦可通路。protected
class 類名{
public: // 公共成員
protected: // 保護成員
private: // 私有成員
};
- 類成員可為類對象。
- 【成員函數的聲明與定義】:類外定義類成員函數的話,必須将類内的成員函數聲明放在類定義的前面,否則編譯出錯。【将類成員函數的定義實作放在類體外有利于接口和實作的分離】
- 【成員函數的隐式内聯】:類成員函數僅在定義置于類體外,且聲明與定義均無
修飾的情況下為非内聯函數。inline
- 【成員函數的重載與預設參數設定】:類成員函數的重載和預設參數的設定必須在類成員函數的第一次聲明或定義的地方。
- 【成員函數的存儲】:同一個成員函數的代碼公用一段存儲空間,即不重複存儲副本。而且C++将類成員函數的代碼存儲在類對象之外的記憶體區域,故
計算類對象的大小時隻計算出類對象的資料成員的大小總和。sizeof
- 一個源檔案中同一個類不能重複定義;類的定義通常放在頭檔案中,由此可保證每個使用該類的檔案都以同樣的方式定義類。
- 【前向聲明】:可以隻聲明一個類但不定義。此時不能定義該類的對象,隻能用于定義指向該類的指針和引用,或者用于以此類為形參類型或傳回值類型的函數的聲明。
- 将類執行個體化之前必須已經确定類的定義,否則編譯出錯。類的成員不能是該類本身,否則因遞歸定義而無法确定該類。
第26講:對象的定義和使用
- 類對象一般用動态記憶體配置設定。
- 【類成員的通路】:
;對象名.成員名
;對象指針->成員名
。對象引用.成員名
- 類對象之間可整體指派。
- 類對象、類對象指針、類對象引用可作為函數參數及函數的傳回值。
第27講:構造函數
- 【構造函數】:定義類的時候并未産生類實體,是以未發生類成員的初始化。但是私有或者保護成員在類體外又無法初始化,是以構造函數是必須的。構造函數在類實體化時自動地被系統調用,以此達到給類對象初始化的目的。
- 【定義構造函數】:C++規定構造函數的名字與類的名字相同,一般在類内聲明而在類體外定義,且不能指定傳回類型,形參可有可無,此外構造函數可聲明為内聯的。
- 構造函數是在建立對象時自動執行的,且隻執行一次,此外還不能人為調用;構造函數一般聲明為
,否則隻能在類内部建立對象并初始化,這不是通常的做法;構造函數應該為每個資料成員初始化,且不應加入與初始化無關的内容;帶參構造函數在初始化時傳入不同的參數即可進行不同的初始化。public
#include<iostream>
#include<stdio.h>
using namespace std;
class Cuboid {
public:
Cuboid(int l, int h, int d);
int volume() {
return length*height*depth;
}
private:
int length, height, depth;
};
Cuboid::Cuboid(int l, int h, int d) {
// 一般長的構造函數定義放在類外實作
length = l;
height = h;
depth = d;
cout<<"length,height,depth="<<l<<","<<h<<','<<d<<endl;
}
int main() {
Cuboid a(1, 2, 3);
cout<<"Volume="<<a.volume()<<endl;
Cuboid b(10, 20, 30);
cout<<"Volume="<<b.volume()<<endl;
return 0;
}
- 【構造函數的初始化清單】:與其他函數不同的是,構造函數可有初始化清單。
類名(形式參數清單):初始化階段{
普通計算階段
}
第28講:預設構造函數和指派構造函數
- 有時候(成員類沒有預設構造函數、成員為引用類型、成員為
型)必須提供類構造函數的初始化清單。如果另一個類定義時直到調用其成員類的預設構造函數都失敗,則編譯出錯。const
class Point{
private:
int x; // 同類項的成員變量不能一起定義?
int y;
public:
Point(int i, int j){ // 無預設構造函數
x = i, y = j;
}
void print(){cout<<x<<","<<y<<endl;}
};
class pointTest{
private:
point a; // 成員為類對象,能不能在此處給出成員類a的參數?在此無法接受構造函數的實參
public:
pointTest(int i, int j):a(i, j){} // 隻能在構造函數參數清單裡對成員a初始化
};
- 【成員初始化次序】:按資料成員的聲明順序,是以應該避免使用成員初始化成員。
- 【構造函數的重載】:構造函數允許重載,以此達到以不同的方式初始化類資料成員的目的。
class Point{
public:
Point(){x=y=0;} // 無參數的構造函數
Point(int a, int b):x(a),y(b){} // 有參數的構造函數
// 可為構造函數設定預設參數,但預設參數的設定必須放在類體内
// 且構造函數有重載的情況下,要避免預設構造與預設值構造之間的歧義
void display(){cout<<x<<","<<y<<endl;}
private:
int x, y;
};
int main(){
Point m;
m.display();
Point n(1, 2);
n.display();
return 0;
}
第29講:析構函數
- 【析構函數】:清理所建立對象占用的記憶體空間。編譯器總是為一個類合成一個析構函數,但要删除指針成員所指的對象必須顯式地編寫析構函數。程式執行到對象作用域結束處時觸發對象的析構函數;
配置設定的對象被new
時觸發對象的析構函數。delete
- 許多類不需要編寫析構函數,尤其是有構造函數的類。析構函數通常用于釋放類在生命周期中擷取的資源。
- 【析構函數三法則】:顯式析構函數的編寫一般出現在複制構造函數為顯式和指派運算符重載的情況下。
- 先構造的後析構。