歡迎加入QQ:498903810 一起交流、討論知識,裏面有大佬,也有小白,天下碼農一家親,大家一起討論進步。
C++ 學習路線
類與類的關係
繼承
多態
文件操作
錯誤處理機制
- 異常
模板(泛式編程)
STL標準庫
C++進階
動態庫、靜態庫
重載原理(函數指針)
智能指針:vptr—>多態
day19
doxygen—>生成代碼文檔
你們懂我… … —> 假裝這裏有一個苦笑
簡介
開源跨平臺的註釋文檔生成工具。
條件
安裝cmake:yum -y install cmake
安裝
- 下載
- 解壓
tar zxvf doxygen壓縮包
- 切換到解壓後的doxygen主目錄
cd doxygen解壓目錄
- 創建
build
目錄mkdir build
- 切換到
build
目錄cd build
- 生成Linux Makefile
cmake -G "Unix Makefiles" ../
- 編譯
make
- 安裝
make install
使用
- 進入項目目錄
cd 項目目錄
- 生成配置文件
doxygen –g
(默認配置文件名爲Doxyfile
) - 生成文檔文件
doxygen
配置文件
# 項目名稱,將作爲於所生成的程序文檔首頁標題
PROJECT_NAME = “Test”
# 文檔版本號,可對應於項目版本號,譬如 svn、cvs 所生成的項目版本號
PROJECT_NUMBER = "1.0.0
# 程序文檔輸出目錄
OUTPUT_DIRECTORY = /home/user1/docs
# 程序文檔輸入目錄
INPUT = /home/user1/project/kernel
# 程序文檔語言環境
OUTPUT_LANGUAGE = Chinese
DOXYFILE_ENCODING = UTF-8
# 只對頭文件中的文檔化信息生成程序文檔
FILE_PATTERNS =
# 遞歸遍歷當前目錄的子目錄,尋找被文檔化的程序源文件
RECURSIVE = YES
# 如果是製作 C 程序文檔,該選項必須設爲 YES,否則默認生成 C++ 文檔格式
OPTIMIZE_OUTPUT_FOR_C = YES
#提取信息,包含類的私有數據成員和靜態成員
EXTRACT_ALL = yes
EXTRACT_PRIVATE = yes
EXTRACT_STATIC = yes
# 對於使用 typedef 定義的結構體、枚舉、聯合等數據類型,只按照 typedef 定義的類型名進行文檔化
TYPEDEF_HIDES_STRUCT = YES
# 在 C++ 程序文檔中,該值可以設置爲 NO,而在 C 程序文檔中,由於 C 語言沒有所謂的域/名字空間這樣的概念,所以此處設置爲 YES
HIDE_SCOPE_NAMES = YES
# 讓 doxygen 靜悄悄地爲你生成文檔,只有出現警告或錯誤時,纔在終端輸出提示信息
QUIET = YES
# 遞歸遍歷示例程序目錄的子目錄,尋找被文檔化的程序源文件
EXAMPLE_RECURSIVE = YES
# 允許程序文檔中顯示本文檔化的函數相互調用關係
REFERENCED_BY_RELATION = YES
REFERENCES_RELATION = YES
REFERENCES_LINK_SOURCE = YES
# 不生成 latex 格式的程序文檔
GENERATE_LATEX = NO
# 在程序文檔中允許以圖例形式顯示函數調用關係,前提是你已經安裝了 graphviz 軟件包
HAVE_DOT = YES
CALL_GRAPH = YES
CALLER_GRAPH = YES
#在最後生成的文檔中,把所有的源代碼包含在其中
SOURCE BROWSER = YES
$這會在HTML文檔中,添加一個側邊欄,並以樹狀結構顯示包、類、接口等的關係
GENERATE TREEVIEW = ALL
語法簡介
- 簡單註釋
- 單行註釋:
///
或者//!
- 多行註釋:
/**
或者/*!
- 單行註釋:
- 文件註釋
/**
* @file 文件名
* @brief 簡介
* @details 細節
* @mainpage 工程概覽
* @author 作者
* @version 版本號
* @date 年-月-日
*/
- 全局常量/變量/宏定義/結構體定義/類定義的註釋
- 代碼前註釋
/// 註釋
全局常量/變量/宏定義/結構體定義/類定義
例如:
/// 緩存大小
#define BUFSIZ 1024*4
- 代碼後註釋
全局常量/變量/宏定義/結構體定義/類定義 ///< 註釋
例如:
#define BUFSIZ 1024*4 ///< 緩存大小
- 函數註釋
/**
* @brief 函數簡介
*
* @param 形參 參數說明
* @param 形參 參數說明
* @return 返回值說明
*/
例如:
/**
* @brief 主函數
* @details 程序唯一入口
*
* @param argc 命令參數個數
* @param argv 命令參數指針數組
* @return @c 0 程序執行成功
* @c 1 程序執行失敗
*/
int main(int argc, char* argv[]){
}
命令 | 生成字段名 |
---|---|
@param |
參數 |
@return |
返回值 |
@p |
參數(後面緊接單詞是參數) |
@c |
代碼(後面緊接單詞是代碼) |
* 其它常用命令
命令 | 生成字段名 | 說明 |
---|---|---|
@attention |
注意 | |
@bug |
缺陷 | 鏈接到所有缺陷彙總的缺陷列表 |
@warning |
警告 | |
@see |
參考 | |
@code |
代碼塊開始 | 與@endcode 成對使用 |
@endcode |
代碼塊結束 | 與@code 成對使用 |
@todo |
TODO | 鏈接到所有TODO 彙總的TODO 列表 |
cppcheck—>靜態檢查代碼的工具
你們懂我… … —> 假裝這裏有一個苦笑
簡介
靜態代碼檢查工具,支持c, c++ 代碼;
- 自動變量檢查
- 數組的邊界檢查
- class類檢查
- 過期的函數,廢棄函數調用檢查
- 異常內存使用,釋放檢查
- 內存泄漏檢查,主要是通過內存引用指針
- 操作系統資源釋放檢查,中斷,文件描述符等
- 異常STL 函數使用檢查
- 代碼格式錯誤,以及性能因素檢查
安裝
- 下載
- 解壓
tar -zxvf cppcheck-版本號.tar.gz
- 進入目錄
cd cppcheck-版本號
- 編譯
make
使用
- 多線程檢測
cppcheck -j 線程數 --enable=檢查級別 檢查目錄
檢查級別分爲all
style
information
運算符重載
友元函數
之前已經說過了友元函數,這裏再提一下下,這裏纔是友元函數的主要用途。
作用:類外函數訪問類內的私有屬性
分類:
- 全局友元函數:將全局函數聲明成友元函數
- 友元成員函數:類的提前引用聲明,將一個函數聲明爲多個類的友元函數
- 友元類:將整個類聲明爲友元函數
特點:
- 友元關係單向性
- 友元關係不可傳遞
友元函數重載運算符常用於運算符的左右操作數類型不同的情況。
函數重載的規則
- 不能重載的運算符:成員運算符
.
、作用域運算符::
、sizeof
、條件運算符?:
- 不允許用戶自定義新的運算符,只能對已有的運算符進行重載
- 重載運算符不允許改變運算符原操作數的個數
- 重載運算符不能改變運算符的優先級
- 重載運算符函數不能有默認的參數,會導致參數個數不匹配
重載<< 和 >> 操作符
重載
<<
和>>
操作符必須使用友元函數,且形參必須爲引用,因爲cout,cin不允許被拷貝
#include <iostream>
#include <cstring>
using namespace std;
class String
{
public:
String(const char * str = NULL):size(0), str(NULL)
{
if(NULL != str)
{
this->size = strlen(str);
this->str = new char[size + 1];
strncpy(this->str, str, this->size);
this->str[size] = '\0';
}
else
{
this->str = new char[1];
this->str[0] = '\0';
size = 0;
}
}
String(const String & obj)
{
if(NULL != obj.str)
{
this->str = new char[size + 1];
strncpy(this->str, obj.str, size);
this->str[size];
this->size = obj.size;
}
}
String & operator=(const String & obj)
{
if(this != &obj)
{
if(this->str != NULL)
{
delete []this->str;
this->str = NULL;
}
this->size = obj.size;
this->str = new char[this->size + 1];
strncpy(this->str, obj.str, size);
this->str[size] = '\0';
}
return *this;
}
friend ostream & operator<<(ostream &out, String &obj);
friend istream & operator>>(istream &in, String &obj);
~String()
{
if(NULL != this->str)
delete []str;
this->size = 0;
}
void Print()
{
cout << str;
}
private:
int size;
char * str;
};
ostream & operator<<(ostream &out, String & obj)//重載<<操作符
{
out << obj.str;
return out;
//return out << obj.str;//聯式編程
}
istream & operator>>(istream &in, String & obj)//重載<<操作符
{
char tmp[1024] = {0};
in >> tmp;
if(*tmp != '\0')
{
obj.size = strlen(tmp);
if(obj.str != NULL)//釋放原來的內存空間
{
delete [] obj.str;
obj.str = NULL;
}
obj.str = new char[obj.size + 1];//申請新的內存空間
strncpy(obj.str, tmp, obj.size);//拷貝數據
obj.str[obj.size] = '\0';//補尾
}
return in;
}
int main()
{
String s1;
s1.Print();
String s("hello world");
cout << s << endl;
cin >> s;
cout << s <<endl;
return 0;
}
注:不能重載的運算符:.、 ::、 .、 ?:、 sizeof。*
只能通過成員函數進行重載操作符:=、[]、()、-> 。
重載=、+、+=、==、!=、-運算符,比較:if(10 == c)、 if(c == 10),左右操作數不同時的運算符重載
重載==運算符時,
==
比較時,必須是友元函數,且形參需要加const
修飾符號友元函數重載運算符常用於運算符的左右操作數類型不同的情況。
#include <iostream>
using namespace std;
class Complex
{
public:
Complex(double real = 0, double imag = 0):real(real), imag(imag){}
void Print()
{
cout << "real = " << real << " imag = " << imag << endl;
}
Complex operator=(const Complex &obj);
Complex operator+(const Complex & obj);
Complex operator+=(const Complex & obj);
bool operator==(const Complex & obj);//第一種
bool operator!=(const Complex & obj);
friend Complex operator-(Complex &ret, const Complex & obj);
friend bool operator==(const Complex & obj,const double &i);
friend bool operator==(const double &i, const Complex & obj);
private:
double real;
double imag;
};
//重載=運算符
Complex Complex::operator=(const Complex &obj)
{
this->imag = obj.imag;
this->real = obj.real;
return *this;
}
//重載+運算符
Complex Complex::operator+(const Complex & obj)
{
return (Complex(this->real + obj.real, this->imag + obj.imag));
}
//重載+=運算符
Complex Complex::operator+=(const Complex & obj)
{
*this = *this + obj;
return *this;
}
//重載==運算符
bool Complex::operator==(const Complex & obj)
{
if(this->imag == obj.imag && this->real == obj.real)
return true;
else
return false;
}
//重載!=運算符
bool Complex::operator!=(const Complex & obj)
{
if(!(*this == obj))
return true;
else
return false;
}
//友元重載-運算符
Complex operator-(Complex &ret, const Complex & obj)
{
return Complex(ret.real - obj.real, ret.imag - obj.imag);
}
//第二種 --->重載==比較類型不同數據類型,用友元函數
bool operator==(const Complex & obj, const double &i)
{
return obj.imag == 0 && obj.real == i;
}
//第三種 --->重載==比較類型不同數據類型,用友元函數
bool operator==(const double &i, const Complex & obj)
{
return obj.real == i && obj.imag == 0;
}
int main()
{
Complex c1(1, 2);
Complex c2(1, 2);
Complex c3;
c3 = c1 + c2;
c3.Print();
c3 += c1;
c3.Print();
c3 = c3 - c1;
c3.Print();
if(c3 == c1)
cout << "c3等於c1" << endl;
else
cout << "c3不等於c1" << endl;
if(c1 != c2)
cout << "c1不等於c2" << endl;
else
cout << "c1等於c2" << endl;
if(c3 == 10)
cout << "c3等於10" << endl;
else
cout << "c3不等於10" << endl;
if(10 == c3)
cout << "10等於c3" << endl;
else
cout << "10不等於c3" << endl;
return 0;
}
運行結果:
real = 2 imag = 4
real = 3 imag = 6
real = 2 imag = 4
c3不等於c1
c1等於c2
c3不等於10
10不等於c3
重載 前置++、後置++、前置–、後置–
#include <iostream>
using namespace std;
class Complex
{
public:
Complex(int real = 0, int imag = 0):real(real), imag(imag){}
Complex operator++();//前置++,成員函數
friend Complex operator++(Complex & obj, int);//後置++,友元函數
Complex operator--();//前置--,成員函數
friend Complex operator--(Complex & obj, int);//後置--,友元函數
friend ostream & operator<<(ostream &out, Complex &obj);//重載<<運算符
private:
int real;
int imag;
};
//前置++,成員函數
Complex Complex::operator++()
{
this->real++;
this->imag++;
return *this;
}
//後置++,友元函數
Complex operator++(Complex & obj, int)
{
Complex tmp = obj;
obj.real++;
obj.imag++;
return tmp;
}
//前置--,成員函數
Complex Complex::operator--()
{
this->real--;
this->imag--;
return *this;
}
//後置--,友元函數
Complex operator--(Complex & obj, int)
{
Complex tmp = obj;
obj.real--;
obj.imag--;
return tmp;
}
//重載<<運算符
ostream & operator<<(ostream &out, Complex &obj)
{
cout << "real = " << obj.real << " image = " << obj.imag << endl;
return out;
}
int main()
{
Complex ct1;
Complex ct2;
Complex ct3;
Complex ct4;
Complex c1 = ct1--;
Complex c2 = --ct2;
Complex c3 = ct3++;
Complex c4 = ++ct4;
cout << "c1 = " << c1 << endl;//後置自減
cout << "ct1 = " << ct1 << endl;
cout << "c2 = " << c2 << endl;//前置自減
cout << "ct2 = " << ct2 << endl;
cout << "c3 = " << c3 << endl;//後置自增
cout << "ct3 = " << ct3 << endl;
cout << "c4 = " << c4 << endl;//前置自增
cout << "ct4 = " << ct4 << endl;
return 0;
}
運行結果:
c1 = real = 0 image = 0//後置自減
ct1 = real = -1 image = -1
c2 = real = -1 image = -1//前置自減
ct2 = real = -1 image = -1
c3 = real = 0 image = 0//後置自增
ct3 = real = 1 image = 1
c4 = real = 1 image = 1//前置自增
ct4 = real = 1 image = 1
繼承
語法:
class 派生類:[訪問限定符] 基類
{
//成員
}
#include <iostream>
#include <cmath>
using namespace std;
class Triangle//三角形
{
public:
Triangle(int a, int b, int c):a(a), b(b), c(c)
{
if(IsValidate())
;
else
{
cout << "輸入的值有錯誤" << endl;
cout << "已經重置爲0, 0, 0" << endl;
a = 0;
b = 0;
c = 0;
}
}
bool IsValidate() const
{
return a < c + b && c < a + b && b < a + c;
}
int GetTotalLength()
{
if(a && b && c)
{
return a + b + c;
}
else
return 0;
}
double GetArea() const
{
if(a && b && c)
{
double half = (a + b + c) / 2.0;
return sqrt((half - a) * half + (half - b) * half + (half - c) * half);
}
return 0;
}
private:
int a;
int b;
int c;
};
class IsoTriangle:public Triangle
{
public:
IsoTriangle(int iso, int side):Triangle(iso, iso, side){};
private:
};
int main()
{
Triangle t(3, 4, 5);
cout << "周長 = " << t.GetTotalLength() << endl;
cout << "面積 = " << t.GetArea() << endl;
IsoTriangle iso(3,4);
cout << "周長 = " << iso.GetTotalLength() << endl;
cout << "面積 = " << iso.GetArea() << endl;
return 0;
}