C++ 介绍

发布时间: 更新时间: 总字数:4228 阅读时间:9m 作者: IP上海 分享 网址
专栏文章
  1. 顺序表的基本操作
  2. 链表
  3. C++ 单链表的基本操作
  4. 栈和队列的基本操作
  5. C++ 二叉树的基本操作
  6. 图的基本操作
  7. C++ 哈夫曼编码
  8. C++ 排序的基本操作
  9. C++ 双向链表的基本操作
  10. 顺序表的基本操作
  11. MFC中如何用ADO连接SQL Server 2005
  12. MFC使用ADO连接SQL Server数据库
  13. VC6 MFC中ClassView视图中无法显示某个类的问题
  14. rose生成C++源代码
  15. 解决<compilation debug="true" targetFramework="4.0"> 问题
  16. Cpp
  17. Cpp
  18. LLDB 调试工具介绍
  19. ccache C/C++ 高速编译工具
  20. LLVM/Clang 介绍
  21. CMake 使用介绍

C++ 语言介绍

介绍

C++是一种被广泛使用的计算机程序设计语言。它是一种通用程序设计语言,支持多重编程范式,例如过程化程序设计、数据抽象、面向对象程序设计、泛型程序设计和设计模式等。

比雅尼·斯特劳斯特鲁普博士在贝尔实验室工作期间在20世纪80年代发明并实现了C++。

安装

brew install cpp

基础知识

  • C 语言标准头文件 math.hstdio.h 在 C++ 中命名为 cmathcstdio
#include <cmath>
#include <cstdio>

int main()
{
  double a = 9.9;
  a = sqrt(a);
  printf("%lf\n", a);
  return 0;
}

typedef

  • typedef 类型别名
#include <iostream>
using namespace std;

typedef int INT;

int main() {
  INT i = 1;
  cout << i << endl;
  return 0;
}

注释

多行注释
/*
  xxxx
*/

单行注释
// xxx

字符串 string

本质为:

typedef std::basic_string<char> string;
#include <iostream>
#include <string>
using namespace std;
typedef string String;

int main() {
  // 默认构造函数,没有参数
  string s1;
  // 赋值运算
  s1 = "hello";
  cout << s1 << endl;

  // 拷贝构造函数,等价于 string s2 = "hello";
  string s2("hello");
  cout << s2 << endl;

  // 拷贝构造函数
  String s3("world!");
  cout << s3 << endl;

  // args: (C string, number of chars)
  string s4("this is a C string", 10); // output is "this is a "
  cout << "s4 is " << s4 << endl;

  // args: (C++ string, start position, number of characters)
  string s5(s4, 3, 3);
  cout << "s5 is " << s5 << endl;

  // args: (number of characters, char)
  string s6(6, '#');
  cout << "s6 is " << s6 << endl;

  // args: (start, end)
  string s7(s4.begin(), s4.end()-3);
  cout << "s7 is " << s7 << endl;

  string s8 = s7 + s6;
  cout << "s8 is " << s8 << endl;

  for(int i=0; i!=s8.size(); i++) {
    cout << i << " " << s8[i] << " ";
  }
  cout << endl;

  // 常量迭代器const_iterator;变量迭代器 iterator
  string::const_iterator ii;
  int i = 0;
  for(ii=s8.begin(); ii!=s8.end(); ii++) {
    cout << i++ << " " << *ii << endl;
  }

  return 0;
}

向量 vector

#include <iostream>
#include <vector>

using std::cin;
using std::cout;
using std::endl;
using std::vector;

int main() {
  // vector 本质为模板函数
  vector<double> x;
  x.resize(3);
  for (vector<double>::size_type i=0; i<3; i++) {
    cin >> x[i++];
  }

  for (vector<double>::iterator it=x.begin(); it!=x.end(); it++) {
    cout << *it << endl;
  }

  return 0;
}

命名空间

  • 命名空间 namespace
    • 作用:防止名字同名冲突
    • 使用运算符 :: 限定某个名字属于哪个命名空间 namespace
    • 常见的3种方法使用名称空间N的param
using namespace N;  // 引入整个命名空间
using N::param;  // 引入单个
N::param;  // 程序中通过命名空间前缀引用
#include <cstdio>
namespace F
{
  int x;
  void f(){
    printf("f...");
  }
  int g() {
    printf("%d\n", x);
    return x;
  }
}

namespace G
{
  double x;
  double g() {
    printf("%lf\n", x);
    return x;
  }
}

int main()
{
  F::x = 1;
  F::g();

  G::x = 3.14;
  G::g();
  return 0;
}

iostream

  • C++的输入输出流库(头文件iostream
    • 输出运算符 <<
    • 输入运算符 >>
  • 标准名字空间 std,包括标准输入输出库
    • cout 代表表输出流(窗口)
    • cin 代表标准输入流(键盘)

引用类型

  • 引用经常用作函数的形参,形参和实参指向同一个对象,修改同时生效
  • 适用于实参内存大时,用引用代替传值提高内存利用率
  • 若函数中不希望修改到实参,可以使用 const 符,如 void swap(int &a, coust int &b)
#include <iostream>
using namespace std;

void swap(int *a, int *b)
{
  cout << "before swap a is " << a << ", b is " << b << endl;
  int t = *a;
  *a = *b;
  *b = t;
  cout << "before swap a is " << a << ", b is " << b << endl;
}

int main()
{
  double a = 9.9;
  double &b = a;  // 相当于 b 是 a 的别名
  b = 3.14;
  cout << "a is " << a << endl;

  int x = 1, y = 2;
  swap(&x, &y);
  cout << "swap x is " << x << ", y is " << y << endl;

  return 0;
}

异常

  • try-catch 处理异常
#include <iostream>
using namespace std;

int main()
{
  int a;
  cout << "Input a: ";
  cin >> a;
  cout << endl;

  try {
    if (a > 100) throw 100;
    if (a < 60) throw "666";
    throw "ok";
  }
  catch (int result) {
    cout << "v is " << a << endl;
  }
  catch (char * s) {
    cout << "s is " << string(s) << endl;
  }
  catch (...) {  // 捕获其他情况
    cout << "ok" << endl;
  }

  return 0;
}
  • 默认参数:函数的形参可以有默认值,但必须放到最右边
#include <iostream>
using namespace std;

int add(int a, int b=60) {
  return a + b;
}

int main() {
  cout << add(1, 2) << endl;
  cout << add(6) << endl;

  return 0;
}
  • 函数重载:C++ 支持函数同名、形参不同(参数个数或参数类型)
    • 调用函数时,编译器将根据实参和形参选择最佳的函数
    • 若存在多个难以区分的最佳函数,报错
    • 不能根据返回值类型区分同名函数
#include <iostream>
using namespace std;

int add(int a, int b=60) {
  return a + b;
}

double add(double a, double b=60) {
  return a + b;
}

int main() {
  cout << add(1, 2) << endl;
  cout << add(3.14) << endl;

  return 0;
}

模板函数

  • 模板函数(template) 编译器自动生成针对指定数据类型的函数
#include <iostream>
using namespace std;

template<class T>
T maxFunc(T a, T b) {
  // return a>b?a:b;
  if(a > b) return a;
  else return b;
}

template<class T1, class T2>
T1 minFunc(T1 a, T2 b) {
  // return a<b?a:b;
  if(a < b) return a;
  else return (T1)b;
}

int main()
{
  int a=3, b=4;
  cout << "max of " << a << ", " << b << " is " << maxFunc(a, b) << endl;

  double x=3.14, y=6.66;
  cout << "max of " << x << ", " << y << " is " << maxFunc(x, y) << endl;

  int c=5;
  double z=8.88;
  cout << "min int of " << c << ", " << z << " is " << minFunc(c, z) << endl;

  return 0;
}

运算符重载

#include <iostream>
using namespace std;

struct Vector {
  double x;
  double y;
};

// 重载 + 运算
Vector operator + (Vector a, Vector b) {
  Vector s;
  s.x = a.x + b.x;
  s.y = a.y + b.y;
  return s;
}

// 重载输出 <<
ostream& operator << (ostream& o, Vector a) {
  o << "(" << a.x << ", " << a.y << ")";
  return o;
}

int main() {
  Vector a, b;
  a.x = 1;
  a.y = 2;
  b.x = 10;
  b.y = 11;

  Vector s = a + b;
  cout << s.x << ", " << s.y << endl;
  operator << (cout, s) << endl;
  cout << s << endl << endl;

  return 0;
}

inline

  • inline 声明内联函数,一般用于不包含循环的简单函数中,编译器通过内联展开,提高运行效率
#include <iostream>
using namespace std;

inline int add(int a, int b)
{
  return a + b;
}

int main()
{
  // 下面2行产生向的代码
  cout << add(1, 2) << endl;
  cout << 1 + 2 << endl;
  return 0;
}

动态内存分配

  • 关键字 newdelete 用来对类对象调用初始化(构造函数)和销毁(析构函数)
    • new 分配的是堆存储空间(所有程序拥有的共享内存空间)
  • C 语音的malloc/alloc/realloc和free类似,C++是升级版本
#include <iostream>
#include <cstring>
using namespace std;

int main()
{
  // 申请一块存放double值的内存块
  double pi = 3.14;
  // 指针变量,保存double类型的地址变量;pp值的类型为double *
  double *pp;
  // 取地址运算符&用来获取 pi 变量的地址;pp 和 *pi 都是double *类型
  pp = &pi;
  // 解引用运算符*用来获取指针变量指向的变量
  *pp = 6.66;

  cout << "*pp = " << *pp << " pi = " << pi << endl;

  cout << "Input a number: ";
  cin >> *pp;  // 输入的变量pp指向double内存块的值
  cout << "*pp = " << *pp << " pi = " << pi << endl;

  // new 用来分配容量为 double 值的内存块,并返回改内存块的地址,类型为 double *;该地址被保存在pp中,pp指向新内存块,该内存块的值是未知的
  // new 对 double 类型的元素调用 double 的构造函数做初始化
  pp = new double;
  // 初始化
  *pp = 3.14;
  cout << "Input a number: ";
  cin >> *pp;  // 输入的变量pp指向double内存块的值
  cout << "*pp = " << *pp << endl;

  // delete 释放动态分配的内存空间
  delete pp;

  // new 分配可以存放5个double值的内存空间,返回该连续内存空间的起始地址,且指针类型是double *(即第一个double元素的地址);new 是队每个double元素调用double类型的构造函数初始化
  pp = new double[5];
  pp[0] = 3.14;
  pp[1] = pp[0] * 2;
  cout << pp[0] << ", " << pp[1] << endl;

  // delete 释放指向多个double类型的动态分配的内存空间;为每个double类型的元素调用double的析构函数释放内存;不指定 [] 时,仅释放第一个 double 的内存空间
  delete[] pp;

  int l = 5;
  // new 分配指定(随机)大小的double类型元素
  pp = new double[l];
  for(int i=0; i<l; i++) {
    // 通过指针访问元素
    pp[i] = i;
    cout << i << " " << pp[i] << endl;
  }
  double *p = pp;
  for(int i=0; i<l; i++) {
    cout << *(p+i) << " ";
  }
  cout << endl;

  for (double *i=pp, *e=pp+l; i<e; i++) {
    cout << *i << " ";
  }
  cout << endl;
  // delete 可以防止内存泄露
  delete[] pp;

  return 0;
}

类 class

在 C 的 struct 类型上,添加成员函数,从而将一个概念或实体的所有属性组合在一起

struct 形式

#include <iostream>
using namespace std;

struct Date {
  int y, m, d;
  void init(int year, int month, int day) {
    y = year;
    m = month;
    d = day;
  }

  void print() {
    cout << y << "-" << m << "-" << d << endl;
  }

  Date& add(int day) {
    d = d + day;
    // this 指向调用该函数的类型对象指针;*this 是调用该函数的那个对象;返回 *this 就是返回自引用本身,可以实现链式调用
    return *this;
  }

  Date& operator+=(int day){
    d = d + day;
    return *this;
  }
};

int main() {
  Date date;
  date.print();
  // init 方法,对 struct 初始化
  date.init(1991, 8, 18);
  date.print();
  date.add(1).add(3);
  date.print();

  // += 运算符重载
  date += 1;
  date.print();
  (date +=1) += 2;
  date.print();
  return 0;
}

构造函数和析构函数

  • 构造函数是和类名同名且返回值为void的函数,在定义对象时会自动调用
    • 构造函数用于初始化类对象成员,包括申请一些资源,如分配内存、打开文件等
  • 析构函数在类对象被销毁时被自动调用,用来释放该对象占用的资源,如释放内存、关闭文件等
    • 定义:~类名(),不带任何参数,没有返回值
  • 拷贝构造函数:定义一个类对象时,使用同类型的对象初始化新对象
  • 赋值运算符:一个对象赋值给另外一个对象
#include <iostream>
using namespace std;

struct Date {
  int y, m, d;

  // 默认构造函数
  Date(){
    cout << "default constructor invoke!" << endl;
  }

  // 带参构造函数
  Date(int month, int day) {
    m = month;
    d = day;
    cout << "constructor invoke!" << endl;
  }

  // 带参构造函数
  Date(int year, int month, int day=1) {
    y = year;
    m = month;
    d = day;
    cout << "constructor invoke!" << endl;
  }

  void print() {
    cout << y << "-" << m << "-" << d << endl;
  }

};

int main() {
  Date date1;
  date1.print();

  Date date2(1991, 8, 18);
  date2.print();

  return 0;
}

class

  • class 定义的类的成员默认都是私有的(private),外部函数无法通过类对象.成员或函数调用
    • private 定义私有的成员或函数,不对外暴露,一般保存类的私有对象
    • public 定义公有的成员或函数,可以被类外调用
      • public 的公开成员(一般是函数)称为该类的接口,外部函数通过对象.成员或函数访问
    • protected
#include <iostream>
#include <cstring>
using namespace std;

// struct people {
class people {
// private 定义私有的成员和函数
private:
  char *name;
  int age;

// public 定义公开的成员和函数
public:
  people(){
    cout << "default constructor invoke!" << endl;
  }

  // 构造函数,带默认值
  people(char *n="no_name", int a=15) {
    int l = strlen(n);
    name = new char(l+1);
    strcpy(name, n);
    age = a;
    cout << "constructor invoke!" << endl;
  }

  char *get_name() {
    return name;
  }
  void set_name(char *n="no_name") {
    int l = strlen(n);
    name = new char(l+1);
    strcpy(name, n);
  }
  int get_age() { return age; }
  void set_age(int a) { age = a; }

  void print() {
    cout << "{name: " << name << ", age: " << age << "}" << endl;
  }

  // 声明类体外函数
  void print2();

  virtual ~people() {
    delete[] name;
    cout << "destructor invoke!" << endl;
  }
};

// 类体外定义方法(成员函数),必须在类定义中声明,类体外要有类作用域

void people::print2() {
  cout << "{name: " << name << ", age: " << age << "}" << endl;
}

int main() {
  // people p1();
  people p2("zhangsan", 18);
  people p3("lisi", 19);
  // p1.print();
  p2.print();
  p3.print();

  p2.set_name("xyz");
  cout << p2.get_name() << endl;

  // 调用类体外函数
  p2.print2();

  return 0;
}

class 模板

类模板可以将一个类变成类模板模板类,类似于模板函数

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <string>
using namespace std;

template<class T>
class Array {
private:
  int size;
  T *data;

public:
  Array(int s){
    size = s ;
    // data = new T[s];
    data = new T[s];
  }

  T &operator [] (int i) {
    if (i<0 || i >= size) {
      cerr << endl << "Out of range" << endl;
      exit(EXIT_FAILURE);
    }
    else return data[i];
  }

  virtual ~Array() {
    delete[] data;
    cout << "destructor invoke!" << endl;
  }
};

int main() {
  Array<int> arr(5);
  arr[0] = 1;
  arr[1] = arr[0] + 6;

  cout << arr[1] << endl;
  // arr[100] = 3;  // err occur

  Array<string> s(5);
  s[0] = "hello";
  s[1] = "world";

  cout << s[1] << endl;

  return 0;
}

继承和派生

  • 继承(inheritance) 一个派生类(derived class)从一个或多个父类(parent class)/基类(base class)继承父类的属性和行为,也可以扩展自己的属性和行为
  • 派生(derivator)
    • 派生类的指针可以自动转化为基础类指针
  • 虚函数(virtual Functions)
    • 派生类的指针可以自动转化为基类指针,用一个指向基类的指针分布指向基类对象和派生类对象
  • 虚函数(pure virtual function)抽象类(abstract base class)
    • 函数体 =0 的虚函数称为纯虚函数
    • 包含纯虚函数的类称为抽象类
#include <iostream>
#include <string>

using namespace std;

class Animal {
protected:
  std::string name;
public:
  Animal(std::string n) : name(n)
  {}
  virtual void speak();
  // virtual const void speak() = 0;
};

// Animal::Animal(string n) :name(n)  // 初始化成员属性
// {
//   // 等价于 name = n;
// }

void Animal::speak() {
  cout << name << endl;
}

// 继承多个父类,使用 , 分隔;即多重派生类(Multiple inheritance)
class Cow : public Animal
{
public:
  int age;
public:
  Cow(std::string n, int a=1) : Animal(n), age(a)
  {}
  void speak();
};

// 派生类的构造函数仅描述它自己属性和其直接基类的初始值,只能使用父类的构造函数初始化父类的属性
// Cow::Cow(string n, int a) :Animal(n), age(a) {
// }

void Cow::speak() {
  cout << "age is " << age << endl;
  Animal::speak();
}

int main() {
  Cow x("zhangsi", 2);
  x.speak();

  Animal y("lisi");
  y.speak();

  Animal *p = &x;
  p->speak();

  Animal* pp[10];
  int num = 0;

  // Animal* as[100];
}

其他

  • boost 提供免费的、可移植的C++源代码库
  • conan 为C和C++开发人员提供的软件包管理器
  • epezent/implot 即时模式绘图
  • g2o 一种通用的图形优化框架
  • ocornut/imgui 使用 C++ 开发的精简的、依赖性最小的图形用户界面
  • OOQP: Object-Oriented Software for Quadratic Programming
  • catchorg/Catch2 一个现代的、C++原生的、用于单元测试、TDD和BDD的测试框架–使用C++14、C++17和更高版本(C++11支持在v2.x分支,Catch1.x分支上支持C++03)
  • PF_RING 是一个 Linux 内核模块和用户空间框架,可以高速处理数据包,同时为数据包处理应用程序提供一致的 API
  • Open Motion Planning Library (OMPL) 开放式运动规划 C++ 库

ci

  • clang-tidy 静态语义检查
Home Archives Categories Tags Statistics