C++入門(3)

歡迎加入QQ:498903810 一起交流、討論知識,裏面有大佬,也有小白,天下碼農一家親,大家一起討論進步。

C++ 學習路線

類與類的關係

繼承

多態

文件操作

錯誤處理機制

  • 異常

模板(泛式編程)

STL標準庫

C++進階

動態庫、靜態庫

重載原理(函數指針)

智能指針:vptr—>多態

day19

doxygen—>生成代碼文檔

你們懂我… … —> 假裝這裏有一個苦笑

簡介

開源跨平臺的註釋文檔生成工具。

條件

安裝cmake:yum -y install cmake

安裝

  1. 下載
  2. 解壓tar zxvf doxygen壓縮包
  3. 切換到解壓後的doxygen主目錄cd doxygen解壓目錄
  4. 創建build目錄mkdir build
  5. 切換到build目錄cd build
  6. 生成Linux Makefilecmake -G "Unix Makefiles" ../
  7. 編譯make
  8. 安裝make install

使用

  1. 進入項目目錄cd 項目目錄
  2. 生成配置文件doxygen –g (默認配置文件名爲Doxyfile)
  3. 生成文檔文件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++ 代碼;

  1. 自動變量檢查
  2. 數組的邊界檢查
  3. class類檢查
  4. 過期的函數,廢棄函數調用檢查
  5. 異常內存使用,釋放檢查
  6. 內存泄漏檢查,主要是通過內存引用指針
  7. 操作系統資源釋放檢查,中斷,文件描述符等
  8. 異常STL 函數使用檢查
  9. 代碼格式錯誤,以及性能因素檢查

安裝

  1. 下載
  2. 解壓tar -zxvf cppcheck-版本號.tar.gz
  3. 進入目錄cd cppcheck-版本號
  4. 編譯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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章