超女選秀的例子咱們玩了好久,爲了學習的須要,暫時離開美眉們,我將採用實際項目開發的例子來說解類的更多知識。python
在C語言基礎知識中已學習過文件操做,在實際開發中,爲了提升效率,我會把文件操做封裝成一個類,類的聲明以下:linux
// 文件操做類聲明 class CFile { private: FILE *m_fp; // 文件指針 bool m_bEnBuffer; // 是否啓用緩衝區,true-啓用;false-不啓用 public: CFile(); // 類的構造函數 CFile(bool bEnBuffer); // 類的構造函數 ~CFile(); // 類的析構函數 void EnBuffer(bool bEnBuffer=true); // 啓、禁用緩衝區 // 打開文件,參數與fopen相同,打開成功true,失敗返回false bool Open(const char *filename,const char *openmode); // 調用fprintf向文件寫入數據 void Fprintf(const char *fmt, ... ); // 調用fgets從文件中讀取一行 bool Fgets(char *strBuffer,const int ReadSize); // 關閉文件指針 void Close(); };
C++經過 public、protected、private三個關鍵字來控制成員變量和成員函數的訪問權限,它們分別表示公有的、受保護的、私有的,被稱爲成員訪問限定符。所謂訪問權限,就是類外面的代碼訪問該類中成員權限。程序員
在類的內部,即類的成員函數中,不管成員被聲明爲 public、protected 仍是private,都是能夠互相訪問的,沒有訪問權限的限制。ide
在類的外部(定義類的代碼以外),只能經過對象訪問public的成員,不能訪問 private、protected屬性的成員。函數
本節重點介紹 public 和 private,protected 將在之後介紹。學習
private 後面的成員都是私有的,如m_fp和m_bEnBuffer,直到有 public出現纔會變成共有的;public 以後再無其餘限定符,因此 public後面的成員都是共有的。測試
private關鍵字的做用在於更好地隱藏類的內部實現,該向外暴露的接口(能經過對象訪問的成員)都聲明爲public,不但願外部知道、或者只在類內部使用的、或者對外部沒有影響的成員,都建議聲明爲private。this
聲明爲 private 的成員和聲明爲 public 的成員的次序任意,既能夠先出現 private部分,也能夠先出現 public 部分。若是既不寫 private 也不寫 public,就默認爲private。.net
在一個類體中,private 和 public能夠分別出現屢次。每一個部分的有效範圍到出現另外一個訪問限定符或類體結束時(最後一個右花括號)爲止。設計
您可能會說,將成員變量所有設置爲 public 省事,確實,這樣作 99.9%的狀況下都不是一種錯誤,我也不認爲這樣作有什麼不妥;可是,將成員變量設置爲private 是一種軟件設計規範,尤爲是在大中型項目中,仍是請你們儘可能遵照這一原則。
成員變量大都以m_開頭,這是約定成俗的寫法,不是語法規定的內容。以m_開頭既能夠一眼看出這是成員變量,又能夠和成員函數中的參數名字區分開。
例如成員函數EnBuffer的函數體以下:
// 啓、禁用緩衝區 void CFile::EnBuffer(bool bEnBuffer) { m_bEnBuffer=bEnBuffer; }
在CFile類的聲明中,有一些特殊的成員函數CFile(),它就是構造函數(constructor)。
CFile(); // 類的構造函數 CFile(bool bEnBuffer); // 類的構造函數
構造函數的名字和類名相同,沒有返回值,不能被顯式的調用,而是在建立對象時自動執行。
構造函數具有如下特色:
1)構造函數必須是 public 屬性。
2)構造函數沒有返回值,由於沒有變量來接收返回值,即便有也毫無用處,不論是聲明仍是定義,函數名前面都不能出現返回值類型,即便是void 也不容許。
3)構造函數能夠有參數,容許重載。一個類能夠有多個重載的構造函數,建立對象時根據傳遞的參數來判斷調用哪個構造函數。
4)構造函數在實際開發中會大量使用,它每每用來作一些初始化工做,對成員變量進行初始化等,注意,不能用memset對整下類進行初始化。
示例
CFile::CFile() // 類的構造函數 { m_fp=0; m_bEnBuffer=true; } CFile::CFile(bool bEnBuffer) // 類的構造函數 { m_fp=0; m_bEnBuffer=bEnBuffer; }
在CFile類的聲明中,還有一個特殊的成員函數\~CFile(),它就是析構函數(destructor)。
~CFile(); // 類的析構函數
析構函數的名字在類的名字前加\~,沒有返回值,但能夠被顯式的調用,在對象銷燬時自動執行,用於進行清理工做,例如釋放分配的內存、關閉打開的文件等,這個用途很是重要,能夠防止程序員犯錯。
析構函數具有如下特色:
1)構造函數必須是 public 屬性的。
2)構造函數沒有返回值,由於沒有變量來接收返回值,即便有也毫無用處,不論是聲明仍是定義,函數名前面都不能出現返回值類型,即便是void 也不容許。
3)析構函數不容許重載的。一個類只能有一個析構函數。
CFile::~CFile() // 類的析構函數 { Close(); // 調用Close釋放資源 }
不少人說C/C++程序很煩鎖,python程序很優雅,說這話人的很荒謬,那是由於他C/C++並不瞭解,只要咱們願意,能夠寫出和python同樣優雅簡潔的代碼,在book210.cpp中,main函數的代碼極爲精簡。
示例(book210.cpp)
/* * 程序名:book210.cpp,此程序演示用C++類的更多知識。 * 做者:C語言技術網(www.freecplus.net) 日期:20190525 */ #include <stdio.h> #include <string.h> #include <stdarg.h> // 文件操做類聲明 class CFile { private: FILE *m_fp; // 文件指針 bool m_bEnBuffer; // 是否啓用緩衝區,true-啓用;false-不啓用 public: CFile(); // 類的構造函數 CFile(bool bEnBuffer); // 類的構造函數 ~CFile(); // 類的析構函數 void EnBuffer(bool bEnBuffer=true); // 啓、禁用緩衝區 // 打開文件,參數與fopen相同,打開成功true,失敗返回false bool Open(const char *filename,const char *openmode); // 調用fprintf向文件寫入數據 void Fprintf(const char *fmt,... ); // 調用fgets從文件中讀取一行 bool Fgets(char *strBuffer,const int ReadSize); // 關閉文件指針 void Close(); }; int main(int argc,char *argv[]) { if (argc !=2) { printf("請輸入待打開的文件名。\n"); return -1; } CFile File; if (File.Open(argv[1],"r")==false) { printf("File.Open(%s)失敗。\n",argv[1]); return -1; } char strLine[301]; while (true) { // 從文件中讀取每一行 if (File.Fgets(strLine,300)==false) break; printf("%s",strLine); // 把從文件中讀到的內容顯示到屏幕 } } CFile::CFile() // 類的構造函數 { m_fp=0; m_bEnBuffer=true; } CFile::CFile(bool bEnBuffer) // 類的構造函數 { m_fp=0; m_bEnBuffer=bEnBuffer; } // 關閉文件指針 void CFile::Close() { if (m_fp!=0) fclose(m_fp); // 關閉文件指針 m_fp=0; } CFile::~CFile() // 類的析構函數 { Close(); // 調用Close釋放資源 } // 啓、禁用緩衝區 void CFile::EnBuffer(bool bEnBuffer) { m_bEnBuffer=bEnBuffer; } // 打開文件,參數與fopen相同,打開成功true,失敗返回false bool CFile::Open(const char *filename,const char *openmode) { Close(); // 打開新的文件以前,若是已經打開了文件,關閉它。 if ( (m_fp=fopen(filename,openmode)) == 0 ) return false; return true; } // 調用fprintf向文件寫入數據 void CFile::Fprintf(const char *fmt,...) { if ( m_fp == 0 ) return; va_list ap; va_start(arg,ap); vfprintf(m_fp,fmt,ap); va_end(ap); if ( m_bEnBuffer == false ) fflush(m_fp); } // 調用fgets從文件中讀取一行 bool CFile::Fgets(char *strBuffer,const int ReadSize) { if ( m_fp == 0 ) return false; memset(strBuffer,0,ReadSize); if (fgets(strBuffer,ReadSize,m_fp) == 0) return false; return true; }
book210運行的效果就是把文件的內容一行一行的顯示出來,類型linux系統的cat命令。
關於類的其它知識,包括this指針、static靜態成員、友元等內容,意義不大,我不介紹了,時間太寶貴,有太多重要的知識要學習,不必把時間浪費在這些不痛不癢又沒什麼實用價值的知識點上,你們之後有時間了再看也行。
咱們已經介紹過printf、fprintf、sprintf、snprintf函數,它們是一組功能類似的函數,而且有一個共同點,就是函數的參數列表是能夠變化的。
函數的聲明以下:
int printf(const char *format, ...); // 格式化輸出到屏幕 int fprintf(FILE *stream, const char *format, ...); // 格式化輸出到文件 int sprintf(char *str, const char *format, ...); // 格式化輸出到字符串 int snprintf(char *str, size_t size, const char *format, ...); // 格式化輸出指定長度的內容到字符串
在實際開發中,咱們的自定義函數也會用到可變參數,實現相似上述函數的功能,例如CFile類的Fprintf成員函數。
C語言採用va_start宏、va_end宏和一系列函數來實現可變參數功能。
void CFile::Fprintf(const char *fmt,...) { if ( m_fp == 0 ) return; va_list ap; va_start(arg,ap); vfprintf(m_fp,fmt,ap); va_end(ap); if ( m_bEnBuffer == false ) fflush(m_fp); }
以CFile類的Fprintf成員函數爲例。
void CFile::Fprintf(const char *fmt,...); // 可變參數自定義函數的聲明方法
va_list指針、va_start宏、va_end宏用於分析參數,難以理解,你們會用就行,我不詳細介紹。
va_list ap; va_start(ap,fmt); vfprintf(m_fp,fmt,ap); va_end(ap);
vfprintf函數把宏分析的結果輸出到文件,還有一系列功能類似的函數,聲明以下:
// 輸出的屏幕 int vprintf(const char *format, va_list ap); // 輸出到文件 int vfprintf(FILE *stream, const char *format, va_list ap); // 輸出到字符串 int vsprintf(char *str, const char *format, va_list ap); // 輸出到字符串,第二個參數指定了輸出結果的長度,相似snprintf函數。 int vsnprintf(char *str, size_t size, const char *format, va_list ap);
1)編寫示例程序,測試類的類成員的訪問權限。
2)編寫示例程序,測試類的構造函數和它的重載,採用gdb跟蹤構造函數的執行過程。
3)編寫示例程序,測試類的析構函數,採用gdb跟蹤析構造的執行過程。
4)編寫示例程序,實現printf、sprintf和snprintf函數的功能,函數的聲明以下:
int myprintf(const char *format, ...); int mysprintf(const char *format, ...); int mysnprintf(const char *format, ...);
5)類定義包括成員變量和成員函數的聲明以及成員函數的定義,在實際開發中,咱們一般將公共類的聲明放在頭文件中(如_public.h),成員函數的定義放在程序文件中(如_public.cpp),請按這種方式修改book210.cpp程序,增長_public.h和_public.cpp程序,修改makefile。
C語言技術網原創文章,轉載請說明文章的來源、做者和原文的連接。
來源:C語言技術網(www.freecplus.net)
做者:碼農有道
若是這篇文章對您有幫助,請點贊支持,或在您的博客中轉發個人文章,謝謝!!!若是文章有錯別字,或者內容有錯誤,或其餘的建議和意見,請您留言指正,很是感謝!!!