1. C++程式設計簡介
學習目标:培養面向對象的觀念,能寫出正規的、大氣的代碼。
1.1 C++分類
-
Object Base 基于對象
C++ with pointer : String
C++ without pointer : Complex
-
Object Oriented 面向對象
繼承
委托等
1.2 C++ 發展
C -> new C -> C with class -> C++
c++98 (1.0)
c++11(2.0)
2. 頭檔案與類的聲明
2.1 C 與C++的比較
- C 将 data 與 function 分開, 是以, 函數(funciton)可以被任意一個資料調用,是以,data是全局的。C的代碼超過5000行就很難掌控。
- C++将data與function封裝在類裡面,并建立了類型。在類型中,data一般是private,私有的。C++通過通路權限來很好的解決了大型項目開發的問題。
2.3 頭檔案中的防衛式聲明(guard)
#ifndef _COMPLEX_
#define _COMPLEX_
.
.//寫頭檔案
.
#endif
- 防衛式聲明主要是為了防止重複include,是在大學教學裡面很容易被忽視的東西,但是在實際項目開發中卻是很常用的,而且很多筆試題目都喜歡考防衛式聲明的編寫。
2.5 書寫第一個class
#ifndef _COMPLEX_
#define _COMPLEX_
#include <iostream>
//class .....
class complex; //前置聲明區
class complex{
// 類的聲明
};
complex::function(){
//類的定義
}
#endif
一般類的書寫,就分為三大塊,基本來說,先寫類的聲明,類的定義,最後根據想法,再決定是否需要寫前置聲明。
2.6 class的聲明
class complex //class head
{
//class body
public:
complex (double r = 0, double i = 0): re (r), im (i) { }
complex& operator += (const complex&);
double real () const { return re; }
double imag () const { return im; }
private:
double re, im;
};
類的聲明由類名與類的主體構成,一般類的data都是私有的。
2.7 模闆的初探
對于上面的代碼,如果data換成 int, float,或者是其他類型的話,那是不是意味着要相應的寫出對應的類呢?那這不是重複勞動了麼。而模闆的出現恰好解決了這個問題。
template<typename T>
class complex //class head
{
//class body
public:
complex (double r = 0, double i = 0): re (r), im (i) { }
complex& operator += (const complex&);
double real () const { return re; }
double imag () const { return im; }
private:
T re, im;
};
complex<int> A(0,5);
complex<double> D(1.1,6.2);
通過模闆,将所要求的類型,通過T進行綁定。如果我要用int,那就指定T為int。
3. 構造函數
3.1 inline函數
class complex{
};
inline void complex::function(){}
在建構類,class,的時候,class body裡面是類的本體,無需添加内聯函數。而如果聲明在本體,定義在外部,則考慮添加内聯函數。
或者更廣泛的來說,在C++裡面調用類的相關函數的時候,都可以加上inline。
inline與宏類似,但是還是有一定的差別。
- inline 定義的類的内聯函數,函數的代碼被放入符号表中,在使用時直接進行替換,(像宏一樣展開),沒有了調用的開銷,效率也很高。
- 隻是做預處理器符号表中的簡單替換,是以它不能進行參數有效性的檢測,也就不能享受C++編譯器嚴格類型檢查的好處.
3.2通路級别 (access level)
class complex{
public:
private:
};
通路級别來講的話,一般大部分的函數都放在public裡面,幾乎全部的資料都是放在private裡面。
3.3 構造函數constructor(ctor)
class complex{
public:
complex(double r = 0, double i = 0)
:re(r), im(i)
{...}
private:
double re, im;
};
書寫構造函數的四個注意點:
- 構造函數的函數名與類名相同
- 構造函數沒有傳回值。(構造函數不會被外部調用,隻有在建立類的對象的時候被使用,是以建立的對象,那就是類本身,無需傳回值)。
- 構造函數允許有預設參數(default argument)
- 構造函數特有初始化清單(initization list)。每次初始化的時候,都應用初始化清單 initization list 初始化
一個變量的生成分成兩個階段,初始化和指派。如果不用初始化清單對成員變量進行指派,則跳過了初始化階段,這樣雖然也對,但是效率降低。
一般而言,不帶指針的類類裡面,大部分是不需要寫析構函數。
構造函數,是可以被重載的,但是被重載時要避免有歧義的代碼,尤其是當構造函數中有預設參數的時候,更應該仔細考慮。
例如:
class complex
{
public:
complex(double r = 0, double i = 0)
:re(r), im(i)
{...}
1) complex()
:re(0), im(0)
{...}
private:
double re, im;
};
這段代碼中的 1) 就是重載失敗的案例,如果使用者調用,complex()初始化的話,就會讓編譯器無法知道調用哪個構造函數而産生錯誤。