Skip to content

C++生态技术栈 ​

重要通知

。

基本概况 ​

是一种高级语言,它是由 Bjarne Stroustrup 于 1979 年在贝尔实验室开始设计开发,进一步扩充和完善了 C 语言,是一种面向对象的程序设计语言。

环境配置与部署 ​

# 检测是否安装
> gcc -v
> pip -V

# 编译运行
> 编译:gcc [name].c
> 执行:./a.out

# 使用 -o 选项指定可执行程序的文件名
> gcc [name].cpp -o [name]
> ./[name].out



# 检测版本
> g++ -v

编译器 ​

扩展名:.cpp | .cp | .c(C语言) 头文件:.h | .hpp文件 静态链接库:.lib文件 动态链接库:.dll文件

自动编译执行插件 ​

Code runner

#include <iostream>
#include <string>

using namespace std;


cout <<  << endl;

指针与引用 ​

  • 每一个变量都有一个内存位置,每一个内存位置都定义了可使用连字号(&)运算符访问的地址,它表示了在内存中的一个地址。
  • 指针是一个变量,其值为另一个变量的地址,即,内存位置的直接地址。
int  var = 20;
int  *ip;
ip = &var;

cout << var << endl;
cout << ip << endl;
  • 引用 &
  • 引用变量是一个别名,它是某个已存在变量的另一个名字。
  • 一旦把引用初始化为某个变量,就可以使用该引用名称或变量名称来指向变量。
int i = 17;
int&  r = i;

// 把引用作为参数
void swap(int& x, int& y)
{
   int temp;
   temp = x; /* 保存地址 x 的值 */
   x = y;    /* 把 y 赋值给 x */
   y = temp; /* 把 x 赋值给 y  */
   return;
}

// 把引用作为返回值
double& setValues( int i )
{
  return vals[i];   // 返回第 i 个元素的引用
}

代码示例 ​

#include <iostream>

using namespace std;


class Zoo {
  public:
    // 跑
    void run() {
      cout << "速度: " << speed << endl;
    }
    // 咬
    void bite() {
      cout << "撕咬: " << "咬合力" << endl;
    }
    // 睡眠
    void sleep() {
      cout << "睡眠: " << "" << endl;
    }
    // 吃
    void eat() {
      cout << "吃: " << "" << endl;
    }
    // 搏斗
    void struggle() {
      cout << "搏斗: " << "" << endl;
    }
  private:
    int speed;
    int weight;
    char color;
    char sharp;
};

class Horse {
  // 马
}

class Lion {
  // 狮子
}

class Tiger {
  // 老虎
}

int main() {
  cout << "主函数" << endl;
}

面向对象 ​

多态 ​

/**
 * 多态
 * 调用成员函数时,会根据调用函数的对象的类型来执行不同的函数
 */

函数重载与运算符重载 ​

/**
 * 函数重载 
 * 指一个与之前已经在该作用域内声明过的函数或方法具有相同名称的声明,但是它们的参数列表和定义(实现)不相同
 */ 
#include <iostream>
using namespace std;

class Zoo {
  public:
    void run(int speed) {
      cout << "奔跑速度: " << speed << "整数" << endl;
    }
    void run(double speed) {
      cout << "奔跑速度: " << speed << "浮点数" << endl;
    }
};

int main(void) {
  Zoo horse;
  horse.run(10);
  horse.run(10.345);
}


/**
 * 重载运算符
 * 重载运算符是带有特殊名称的函数,函数名是由关键字 operator 和其后要重载的运算符符号构成
 * 重载运算符有一个返回类型和一个参数列表
 */ 
class Zoo {
  public:
    void run() {
      cout << "体重: " << weight << endl;
    }
  // 重载 + 运算符,用于把两个Zoo对象相加
  Zoo operator+(const Zoo& b) {
    Zoo zoo;
    zoo.weight = this->weight + b.weight;
    return zoo;
  }
  private: 
    int weight = 100;
};

int main() {
  Zoo horse;
  Zoo cattle;
  Zoo pig;
  
  pig = horse + cattle;
  pig.run();
  return 0;
}

继承类型 ​

接口 ​

类 • 对象 • 继承 ​

// 声明类
class Sharp
{
  public:
    double width;  // 盒子的宽度
    double height;   // 盒子的高度
};

int main() {
  return 0;
}

/**
 * 定义派生类
 * 一个类可以派生自多个类,这意味着,它可以从多个基类继承数据和函数
 * 语法:class derived-class: access-specifier base-class
 * access-specifier:访问修饰符 access-specifier 是 public、protected 或 private 其中的一个
 */
class Rect: public Sharp
{
  public:
    int getArea() {
      return (width * height);
    }
};


/**
 * 多继承
 * 语法
  class <派生类名>:<继承方式1><基类名1>,<继承方式2><基类名2>,…
  {
    <派生类类体>
  }; 
 */
class Color {
  public:
    double yellow;
};

class Angle: public Sharp, public Color {

}

数据抽象与数据封装 ​

模板管理

指针与引用

# ########################################
#   #指针
# ########################################
# 背景与动机
> 通过指针,可以简化一些 C++ 编程任务的执行,还有一些任务,如动态内存分配,没有指针是无法执行的。

# 简介与核心思想
> 定义:指针是一个变量,其值为另一个变量的内存地址,即,内存位置的直接地址
> 每一个变量都有一个内存位置,每一个内存位置都定义了可使用连字号(&)运算符访问的地址

# 为什么我不能直接使用变量,而是重新声明一个指针?

# 指针变量声明
> type *var-name;

# 代码示例
#include <iostream>
using namespace std;

int main ()
{
   int  var = 20;   // 实际变量的声明
   int  *ip;        // 指针变量的声明

   // 使用连字号(&)运算符访问的地址
   ip = &var;       // 在指针变量中存储 var 的地址, 0x61ff18
   cout << "Value of var variable: ";
   cout << var << endl;
   // 输出在指针变量中存储的地址
   cout << "Address stored in ip variable: ";
   cout << ip << endl;
   // 访问指针中地址的值
   cout << "Value of *ip variable: ";
   cout << *ip << endl;
 
   return 0;
}


# C++ 指针详解
----------------------------------------------------------------------------------------
  概念	              描述
----------------------------------------------------------------------------------------
  Null                指针	C++ 支持空指针。NULL 指针是一个定义在标准库中的值为零的常量。
  指针的算术运算	     可以对指针进行四种算术运算:++、--、+、-
  指针 vs 数组	      指针和数组之间有着密切的关系。
  指针数组	          可以定义用来存储指针的数组。
  指向指针的指针	     C++ 允许指向指针的指针。
  传递指针给函数	     通过引用或地址传递参数,使传递的参数在调用函数中被改变。
  从函数返回指针	     C++ 允许函数返回指针到局部变量、静态变量和动态内存分配。
----------------------------------------------------------------------------------------




# ########################################
#   #引用
# ########################################
# 背景与动机
> 引用变量是一个别名,也就是说,它是某个已存在变量的另一个名字。一旦把引用初始化为某个变量,就可以使用该引用名称或变量名称来指向变量。
> & 读作引用

# 声明引用
> 

# 代码示例
> 声明一个引用
> 将引用指向一个变量
int i = 17;
int&  r = i;

# 引用 vs 指针
> 不存在空引用。引用必须连接到一块合法的内存。
> 一旦引用被初始化为一个对象,就不能被指向到另一个对象。指针可以在任何时候指向到另一个对象。
> 引用必须在创建时被初始化。指针可以在任何时间被初始化。

变量与常量

# 变量
> 可使用连字号(&)运算符访问的地址
# 代码示例
#include <iostream>
using namespace std;
 
int main ()
{
   int  var1;
   cout << &var1 << endl;
   return 0;
}

# 全局变量
> 在所有函数外部声明的变量

# 局部变量
> 在函数或一个代码块内部声明的变量

# 形式参数
> 在函数参数的定义中声明的变量


# 初始化局部变量和全局变量
> 当局部变量被定义时,系统不会对其初始化,您必须自行对其初始化。定义全局变量时,系统会自动初始化为下列值
--------------------------------
  数据类型	初始化默认值
--------------------------------
  int	     0
  char	   '\0'
  float	   0
  double	 0
  pointer	 NULL
--------------------------------

标识符

# 标识符
> 构成:以字母 A-Z 或 a-z 或下划线 _ 开始,后跟零个或多个字母、下划线和数字(0-9)  
> 标识符内不允许出现标点字符,比如 @、& 和 %。  
> C++ 区分大小写。

存储类

# 背景与动机
> 存储类定义 C++ 程序中变量/函数的范围(可见性)和生命周期。这些说明符放置在它们所修饰的类型之前。

# 存储类
> auto:C++98标准中auto关键字用于自动变量的声明;自 C++ 11 以来,auto 关键字用于两种情况:声明变量时根据初始化表达式自动推断该变量的类型、声明函数时函数返回值的占位符;在C++11中已删除这一用法;  
> register:用于定义存储在寄存器中而不是 RAM 中的局部变量。这意味着变量的最大尺寸等于寄存器的大小(通常是一个词),且不能对它应用一元的 '&' 运算符(因为它没有内存位置)  
> static:指示编译器在程序的生命周期内保持局部变量的存在,而不需要在每次它进入和离开作用域时进行创建和销毁。因此,使用 static 修饰局部变量可以在函数调用之间保持局部变量的值。static 修饰符也可以应用于全局变量。当 static 修饰全局变量时,会使变量的作用域限制在声明它的文件内。    
> extern:用于提供一个全局变量的引用,全局变量对所有的程序文件都是可见的。当您使用 'extern' 时,对于无法初始化的变量,会把变量名指向一个之前定义过的存储位置。  
> mutable:仅适用于类的对象,这将在本教程的最后进行讲解。它允许对象的成员替代常量。也就是说,mutable 成员可以通过 const 成员函数修改。  
> thread_local (C++11):使用 thread_local 说明符声明的变量仅可在它在其上创建的线程上访问。 变量在创建线程时创建,并在销毁线程时销毁。 每个线程都有其自己的变量副本。

多线程

/**
 * 创建线程
 * pthread_create (thread, attr, start_routine, arg) 
 * thread:	指向线程标识符指针
 * attr:一个不透明的属性对象,可以被用来设置线程属性。您可以指定线程属性对象,也可以使用默认值 NULL
 * start_routine:线程运行函数起始地址,一旦线程被创建就会执行
 * arg:运行函数的参数。它必须通过把引用作为指针强制转换为 void 类型进行传递。如果没有传递参数,则使用 NULL
 */

函数与数据结构

/**
 * 声明函数
 * return_type:返回类型,例如 void | int | double
 * function_name: 函数名称
 * parameter list:参数列表。例如 int a, int b
 */
return_type function_name( parameter list )
{
  body of the function
}

// 定义结构
struct TYPE_NAME {
  member_type1 member_name1;
  member_type2 member_name2;
  member_type3 member_name3;
  .
  .
} OBJECT_NAME;

// 示例
struct Books
{
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
} book;

// 访问结构成员
int main() {
  Books book;
  strcpy( book.title, "C++ 教程");
  cout << "第一本书标题 : " << book.title <<endl;
}

命名空间

/**
 * 背景动机 
 * 为了解决在引入不同库中相同名称的函数、类、变量等而引起的冲突,使用命名空间定义不同库的上下文,即定义了一个范围
 */

//定义命名空间
namespace NAMESPACE_NAME {
  // 代码声明
}

// 示例
#include <iostream>

using namespace std;
 
// 第一个命名空间
namespace first_space {
   void func() {
      cout << "Inside first_space" << endl;
   }
}
// 第二个命名空间
namespace second_space {
   void func(){
      cout << "Inside second_space" << endl;
   }
}

int main ()
{
	// 调用第一个命名空间中的函数
	first_space::func();
	// 调用第二个命名空间中的函数
	second_space::func(); 

	return 0;
}


/**
 * using 指令
 * 动机一:简化在使用命名空间时无需在前面加上命名空间的名称
 * 动机二:也可以用来指定命名空间中的特定项目
 */
#include <iostream>
using namespace std;
 
// 第一个命名空间
namespace first_space {
   void func(){
      cout << "Inside first_space" << endl;
   }
}
// 第二个命名空间
namespace second_space{
   void func() {
      cout << "Inside second_space" << endl;
   }
}

using namespace first_space;
int main ()
{
 
   // 调用第一个命名空间中的函数
   func();
   
   return 0;
}


/**
 * 嵌套的命名空间
 * 在一个命名空间中定义另一个命名空间
 */
namespace namespace_name1 {
	// 代码声明
	namespace namespace_name2 {
		// 代码声明
	}
}

// 引用
// 访问 namespace_name2 中的成员
using namespace namespace_name1::namespace_name2;
 
// 访问 namespace:name1 中的成员
using namespace namespace_name1;

数据类型

# 简介与核心思想
> C++ 允许在 char、int 和 double 数据类型前放置修饰符。修饰符用于改变基本类型的含义,所以它更能满足各种情境的需求。

# 数据类型修饰符
> signed:
> unsigned:
> long:
> short:

# 应用
> 修饰符 signed、unsigned、long 和 short 可应用于整型  
> signed 和 unsigned 可应用于字符型  
> long 可应用于双精度型  
> 修饰符 signed 和 unsigned 也可以作为 long 或 short 修饰符的前缀
# 基本的内置类型
> C++ 为程序员提供了种类丰富的内置数据类型和用户自定义的数据类型。下表列出了七种基本的 C++ 数据类型:
类型	关键字
布尔型	bool
字符型	char
整型	int
浮点型	float
双浮点型	double
无类型	void
宽字符型 wchar_t

# 各种变量类型在内存中存储值时需要占用的内存,以及该类型的变量所能存储的最大值和最小值。
> 不同系统会有所差异
类型	位	范围
char	1 个字节	-128 到 127 或者 0 到 255
unsigned char	1 个字节	0 到 255
signed char	1 个字节	-128 到 127
int	4 个字节	-2147483648 到 2147483647
unsigned int	4 个字节	0 到 4294967295
signed int	4 个字节	-2147483648 到 2147483647
short int	2 个字节	-32768 到 32767
unsigned short int	2 个字节	0 到 65,535
signed short int	2 个字节	-32768 到 32767
long int	8 个字节	-9,223,372,036,854,775,808 到 9,223,372,036,854,775,807
signed long int	8 个字节	-9,223,372,036,854,775,808 到 9,223,372,036,854,775,807
unsigned long int	8 个字节	0 到 18,446,744,073,709,551,615
float	4 个字节	精度型占4个字节(32位)内存空间,+/- 3.4e +/- 38 (~7 个数字)
double	8 个字节	双精度型占8 个字节(64位)内存空间,+/- 1.7e +/- 308 (~15 个数字)
long double	16 个字节	长双精度型 16 个字节(128位)内存空间,可提供18-19位有效数字。
wchar_t	2 或 4 个字节	1 个宽字符

# typedef 声明
> 使用 typedef 为一个已有的类型取一个新的名字
> 语法:typedef type newname; 
> 示例:typedef int feet;


# 枚举类型
> 创建枚举,需要使用关键字 enum。枚举类型的一般形式为
enum 枚举名{ 
     标识符[=整型常数], 
     标识符[=整型常数], 
... 
    标识符[=整型常数]
} 枚举变量;
> 示例
enum color { red, green, blue } c;
c = blue;


#include<iostream>  
#include<string>  

using namespace std;


class Type {
  public:
    void init() {
      //
    }
    bool state = true;
    string sex = "male";
  	int age = 23;
    float average = 2.3247364783;
    double rate = 2.3247364783;
};

int main(void)
{
  Type dt;
  char slogan[100] = "May force be with you";

  cout << "布尔型:    " << dt.state << endl;
  cout << "字符型:    " << dt.sex << endl;
  cout << "整型:      " << dt.age << endl;
  cout << "浮点型:    " << dt.average << endl;
  cout << "双浮点型:  " << dt.rate << endl;
  cout << "无类型:    " << slogan[100] << endl;
  cout << "宽字符型:  " << dt.state << endl;

  cout << "C++ module" << endl;
  return 0;
}

修饰符

条件控制

虚函数与纯虚函数的区别

# 虚函数与纯虚函数的歧义
> 定义一个函数为虚函数,不代表函数为不被实现的函数   
> 定义他为虚函数是为了允许用基类的指针来调用子类的这个函数  
> 定义一个函数为纯虚函数,才代表函数没有被实现  


# 虚函数
> 是在基类中使用关键字 virtual 声明的函数
> 背景与动机:在派生类中重新定义基类中定义的虚函数时,会告诉编译器不要静态链接到该函数。
> 我们想要的是在程序中任意点可以根据所调用的对象类型来选择调用的函数,这种操作被称为动态链接,或后期绑定。


# 纯虚函数
> 您可能想要在基类中定义虚函数,以便在派生类中重新定义该函数更好地适用于对象,但是您在基类中又不能对虚函数给出有意义的实现,这个时候就会用到纯虚函数。
# 我们可以把基类中的虚函数 area() 改写如下
class Shape {
  protected:
    int width, height;
  public:
    Shape( int a=0, int b=0)
    {
        width = a;
        height = b;
    }
    // pure virtual function
    virtual int area() = 0;
};
# = 0 告诉编译器,函数没有主体,上面的虚函数是纯虚函数

循环语句

Lambda 函数与表达式

# 简介与核心思想
> 匿名函数:称为 Lambda 函数(也叫 Lambda 表达式)
[capture](parameters)->return-type{body}
[](int x, int y){ return x < y ; }
> 没有返回值
[capture](parameters){body}
[]{ ++global_x; }
[](int x, int y) -> int { int z = x + y; return z + x; }

​

​

​

​

​

​

​

​

​

插件列表 ​

Crypto ​

用C++ 编写的密码类库

大型项目 ​

Linux ​

Kaldi ​

FreeNOS ​

chromium ​

Released under the MIT License.