欢迎加入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;
}