C++ 总结

##C++ 基础

C++ 是一种静态类型的、编译式的、通用的、大小写敏感的、不规则的编程语言,支持过程化编程、面向对象编程和泛型编程 C++ 是 C 的一个超集,事实上,任何合法的 C 程序都是合法的 C++ 程序。

发布时间文档通称备注
2015ISO/IEC TS 19570:2015-用于并行计算的扩展
2015ISO/IEC TS 18822:2015-文件系统
2014ISO/IEC 14882:2014C++14第四个C++标准
2011ISO/IEC TR 24733:2011-十进制浮点数扩展
2011ISO/IEC 14882:2011C++11第三个C++标准
2010ISO/IEC TR 29124:2010-数学函数扩展
2007ISO/IEC TR 19768:2007C++TR1C++技术报告:库扩展
2006ISO/IEC TR 18015:2006-C++性能技术报告
2003ISO/IEC 14882:2003C++03第二个C++标准
1998ISO/IEC 14882:1998C++98第一个C++标准

###类型

类型关键字
布尔型bool
字符型char
整型int
浮点型float
双浮点型double
无类型void
宽字符型wchar_t
类型范围
char1 个字节-128 到 127 或者 0 到 255
unsigned char1 个字节0 到 255
signed char1 个字节-128 到 127
int4 个字节-2147483648 到 2147483647
unsigned int4 个字节0 到 4294967295
signed int4 个字节-2147483648 到 2147483647
short int2 个字节-32768 到 32767
unsigned short int2 个字节0 到 65,535
signed short int2 个字节-32768 到 32767
long int8 个字节-9,223,372,036,854,775,808 到 9,223,372,036,854,775,807
signed long int8 个字节-9,223,372,036,854,775,808 到 9,223,372,036,854,775,807
unsigned long int8 个字节0 to 18,446,744,073,709,551,615
float4 个字节+/- 3.4e +/- 38 (~7 个数字)
double8 个字节+/- 1.7e +/- 308 (~15 个数字)
long double8 个字节+/- 1.7e +/- 308 (~15 个数字)
wchar_t2 或 4 个字节个宽字符

###typedef

使用 typedef 为一个已有的类型取一个新的名字。

typedef int feet;

###枚举

enum color { red=3, green, blue } c;
color cc = blue;
cout << cc << endl;

###变量

可以使用 extern 关键字在任何地方声明一个变量

extern int d = 3, f = 5;    // d 和 f 的声明 
int d = 3, f = 5;           // 定义并初始化 d 和 f

###常量

  • 使用 #define 预处理器
  • 使用 const 关键字
#define LENGTH 10 

const int  LENGTH = 10;

###数组

double balance[10];
double balance[5] = {1000.0, 2.0, 3.4, 17.0, 50.0};
double balance[] = {1000.0, 2.0, 3.4, 17.0, 50.0};
balance[4] = 50.0;
double salary = balance[9];

// 多维数组
int a[3][4] = {  
 {0, 1, 2, 3} ,   /*  初始化索引号为 0 的行 */
 {4, 5, 6, 7} ,   /*  初始化索引号为 1 的行 */
 {8, 9, 10, 11}   /*  初始化索引号为 2 的行 */
};

###判断

// if else
// 局部变量声明
int a = 100;

// 检查布尔条件
if( a < 20 )
{
   // 如果条件为真,则输出下面的语句
   cout << "a 小于 20" << endl;
}
else
{
   // 如果条件为假,则输出下面的语句
   cout << "a 大于 20" << endl;
}

// switch
// 局部变量声明
char grade = 'D';

switch(grade)
{
case 'A' :
  cout << "很棒!" << endl; 
  break;
case 'B' :
case 'C' :
  cout << "做得好" << endl;
  break;
default :
  cout << "无效的成绩" << endl;
}
cout << "您的成绩是 " << grade << endl; 

###循环

  • break 终止循环,且程序流将继续执行紧接着循环的下一条语句。

  • break 用于终止 switch 语句中的一个 case。

  • continue 会跳过当前循环中的代码,强迫开始下一次循环。

// while 循环执行
int a = 10;
while( a < 20 )
{
   cout << "a 的值:" << a << endl;
   a++;
}

// do 循环执行
do
{
   cout << "a 的值:" << a << endl;
   a = a + 1;
}while( a < 20 );

// for 循环执行
for( int a = 10; a < 20; a = a + 1 )
{
   cout << "a 的值:" << a << endl;
}

###运算符

算术运算符:+ - * / % ++ --

  • % 取模运算符,整除后的余数

关系运算符:== != > < >= <= 逻辑运算符:&& || ! 位运算符:& | ^ ~ << >>

  • ^ 如果存在于其中一个操作数中但不同时存在于两个操作数中,二进制异或运算符复制一位到结果中
  • ~ 二进制补码运算符是一元运算符,具有"翻转"位效果,即0变成1,1变成0。
  • << 二进制左移运算符,按二进制形式把所有的数字向左移动对应的位数,高位移出(舍弃),低位的空位补零。左移n位就相当于乘以2的n次方。
  • >> 二进制右移运算符,按二进制形式把所有的数字向左移动对应的位数,高位移出(舍弃),低位的空位补零。右移n位相当于除以2的n次方。

赋值运算符:= += -= *= /= %= <<= >>= &= ^= |=

###函数

函数声明会告诉编译器函数名称及如何调用函数。函数的实际主体可以单独定义。

####传值调用 传值调用方法,把参数的实际值复制给函数的形式参数。在这种情况下,修改函数内的形式参数不会影响实际参数。

// 声明
int maxNum(int num1, int num2);

// 传入2个int参数,其中一个有默认值,返回 int
int maxNum(int num1, int num2) 
{
   // 局部变量声明
   int result;
 
   if (num1 > num2)
      result = num1;
   else
      result = num2;
 
   return result; 
}

####指针调用

指针调用方法,把参数的地址复制给形式参数。在函数内,该地址用于访问调用中要用到的实际参数。这意味着,修改形式参数会影响实际参数。

// 函数定义
void swap(int *x, int *y)
{
   int temp;
   temp = *x;   /* 保存地址 x 的值 */
   *x = *y;     /* 把 y 赋值给 x */
   *y = temp;   /* 把 x 赋值给 y */
  
   return;
}

int main ()
{
   // 局部变量声明
   int a = 100;
   int b = 200;
 
   cout << "交换前,a 的值:" << a << endl;
   cout << "交换前,b 的值:" << b << endl;

   /* 调用函数来交换值
    * &a 表示指向 a 的指针,即变量 a 的地址 
    * &b 表示指向 b 的指针,即变量 b 的地址 
    */
   swap(&a, &b);

   cout << "交换后,a 的值:" << a << endl;
   cout << "交换后,b 的值:" << b << endl;
 
   return 0;
}

####引用调用

引用调用方法,把参数的地址复制给形式参数。在函数内,该引用用于访问调用中要用到的实际参数。这意味着,修改形式参数会影响实际参数。

// 函数定义
void swap(int &x, int &y)
{
   int temp;   
   temp = x; /* 保存地址 x 的值 */
   x = y;    /* 把 y 赋值给 x */
   y = temp; /* 把 x 赋值给 y  */
  
   return;
}

int main ()
{
   // 局部变量声明
   int a = 100;
   int b = 200;
 
   cout << "交换前,a 的值:" << a << endl;
   cout << "交换前,b 的值:" << b << endl;

   /* 调用函数来交换值 */
   swap(a, b);

   cout << "交换后,a 的值:" << a << endl;
   cout << "交换后,b 的值:" << b << endl;
 
   return 0;
}

###Lambda 表达式

C++11 提供了对匿名函数的支持,称为 Lambda 函数(也叫 Lambda 表达式)。 Lambda 表达式把函数看作对象。Lambda 表达式可以像对象一样使用,比如可以将它们赋给变量和作为参数传递,还可以像函数一样对其求值。

在Lambda表达式内可以访问当前作用域的变量,这是Lambda表达式的闭包(Closure)行为。 与JavaScript闭包不同,C++变量传递有传值和传引用的区别。可以通过前面的[]来指定

/*
[]      // 沒有定义任何变量。使用未定义变量会引发错误。
[x, &y] // x以传值方式传入(默认),y以引用方式传入。
[&]     // 任何被使用到的外部变量都隐式地以引用方式加以引用。
[=]     // 任何被使用到的外部变量都隐式地以传值方式加以引用。
[&, x]  // x显式地以传值方式加以引用。其余变量以引用方式加以引用。
[=, &z] // z显式地以引用方式加以引用。其余变量以传值方式加以引用。
*/
[](int x, int y) -> int { int z = x + y; return z + x; }

###指针 *

每一个变量都有一个内存位置,每一个内存位置都定义了可使用连字号(&)运算符访问的地址,它表示了在内存中的一个地址。

指针是一个变量,其值为另一个变量的地址,即,内存位置的直接地址。就像其他变量或常量一样,您必须在使用指针存储其他变量地址之前,对其进行声明。 通过使用一元运算符 * 来返回位于操作数所指定地址的变量的值

所有指针的值的实际数据类型,都是一样的,都是一个代表内存地址的长的十六进制数。 指针所指向的变量或常量的数据类型不同。

#include <iostream>
using namespace std;

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

   ip = &var;       // 在指针变量中存储 var 的地址

   cout << "var 变量的地址: " << &var << endl;
   cout << "var 的值: ";
   cout << var << endl;

   cout << "在指针变量中存储的地址: ";
   cout << ip << endl;

   cout << "指针中地址的值: ";
   cout << *ip << endl;

   return 0;
}

###引用 &

  • 不存在空引用。引用必须连接到一块合法的内存。
  • 一旦引用被初始化为一个对象,就不能被指向到另一个对象。指针可以在任何时候指向到另一个对象。
  • 引用必须在创建时被初始化。指针可以在任何时间被初始化。
int i = 17;
int &r = i;

###输入输出

// 预定义的对象 cerr 是 ostream 类的一个实例。cerr 对象附属到标准错误设备,通常也是显示屏,但是 cerr 对象是非缓冲的,且每个流插入到 cerr 都会立即输出。
cerr << "错误 : cerr" << endl;
// 预定义的对象 clog 是 ostream 类的一个实例。clog 对象附属到标准错误设备,通常也是显示屏,但是 clog 对象是缓冲的。这意味着每个流插入到 clog 都会先存储在缓冲在,直到缓冲填满或者缓冲区刷新时才会输出。
clog << "日志 : clog " << endl;

char name[50];
cout << "请输入您的名称: ";
// 预定义的对象 cin 是 istream 类的一个实例。cin 对象附属到标准输入设备,通常是键盘。cin 是与流提取运算符 >> 结合使用
cin >> name;
// 预定义的对象 cout 是 ostream 类的一个实例。cout 对象"连接"到标准输出设备,通常是显示屏。cout 是与流插入运算符 << 结合使用的
cout << "您的名称是: " << name << endl;

###数据结构(结构体)

#include <iostream>
#include <cstring>

using namespace std;
void printBook( struct Books book ); // 传值调用
void printBook2(struct Books *book); // 指针调用

// struct 语句定义了一个包含多个成员的新的数据类型
struct Books
{
   char  title[50];
   int   book_id;
};

int main( )
{
   struct Books Book1;        // 声明 Book1,类型为 Book

   // Book1 详述
   // strcpy(s1, s2) 复制字符串 s2 到字符串 s1。
   strcpy( Book1.title, "Learn C++ Programming");
   Book1.book_id = 6495407;

   // 传值调用 输出 Book1 信息
   printBook( Book1 );
   // 指针调用
   printBook2(&Book1);

   return 0;
}

// 传值调用
void printBook( struct Books book )
{
    cout << "Book title : " << book.title <<endl;
    cout << "Book id : " << book.book_id <<endl;
}
// 指针调用
void printBook2(struct Books *book){
    cout << "Book title : " << book->title <<endl;
    cout << "Book id : " << book->book_id <<endl;
}

##面向对象

###类

C++ 在 C 语言的基础上增加了面向对象编程

####类的基本概念

#include <iostream>
#include <cstring>

using namespace std;

/*
 * 类定义是以关键字 class 开头,后跟类的名称。
 * 每一个对象都能通过 this 指针来访问自己的地址。this 指针是所有成员函数的隐含参数。
 */
class Box{
// 默认情况下,类的所有成员都是私有的,私有成员变量或函数在类的外部是不可访问的,甚至是不可查看的。只有类和友元函数可以访问私有成员。
private:
    double *ptr; // 指针
    double length;   // 长度 私有
// 保护成员变量或函数与私有成员十分相似,但有一点不同,保护成员在派生类(即子类)中是可访问的。
protected:
    double breadth;  // 宽度 受保护
// 关键字 public 确定了类成员的访问属性。在类对象作用域内,公共成员在类的外部是可访问的。
public:
    Box(); // 构造函数
    Box(double len); // 构造函数
    Box(const Box &obj); // 拷贝构造函数 obj是一个对象引用,用于初始化另一个对象
    ~Box(); // 析构函数

    friend void printLength(Box box); //友元函数

    /*
     * 静态成员
     * 不能把静态成员放置在类的定义中,但是可以在类的外部通过使用范围解析运算符 :: 来重新声明静态变量从而对它进行初始化,
     * 无论创建多少个类的对象,静态成员都只有一个副本。静态成员在类的所有对象中是共享的
     */
    static int objectCount;
    double height;   // 高度
    //成员函数可以定义在类定义内部,或者单独使用范围解析运算符 :: 来定义
    void setLength(double len){
        length = len;
    }
    double getLength(){
        cout << "*ptr=len=" << *ptr << endl;
        cout << "length=" << length << endl;
        return length;
    }

    void setBreadth(double wid);
    double getBreadth();
    //返回体积
    double getVolume(void)
    {
        // 每一个对象都能通过 this 指针来访问自己的地址。this 指针是所有成员函数的隐含参数。
        cout << "getVolume 通过 this 调用 getBreadth = " << this->getBreadth() << endl;
        return this->length * breadth * height;
    }
};

/*
 * 类的构造函数是类的一种特殊的成员函数,它会在每次创建类的新对象时执行。
 * 构造函数的名称与类的名称是完全相同的,并且不会返回任何类型,也不会返回 void。构造函数可用于为某些成员变量设置初始值。
 */
Box::Box(void){
    cout << "执行 构造函数..." << endl;
    ptr = new double;
}
// Box::Box(double len) == Box::Box(double len): length(len)
Box::Box(double len){
    cout << "执行 带参数的构造函数..." << endl;
    length = len;
    ptr = new double;
    *ptr = len;

    // 累加静态成员
    objectCount += 1;
}
/*
 * 拷贝构造函数是一种特殊的构造函数,它在创建对象时,是使用同一类中之前创建的对象来初始化新创建的对象
 * 用于:
 * 1. 通过使用另一个同类型的对象来初始化新创建的对象。
 * 2. 复制对象把它作为参数传递给函数。
 * 3. 复制对象,并从函数返回这个对象。
 *
 * 拷贝构造函数 obj是一个对象引用,用于初始化另一个对象
 */
Box::Box(const Box &obj){
    cout << "执行 拷贝构造函数..." << endl;
    ptr = new double; // 为指针分配内存
    *ptr = *obj.ptr;
}

/*
 * 析构函数是类的一种特殊的成员函数,它会在每次删除所创建的对象时执行。
 * 析构函数的名称与类的名称是完全相同的,只是在前面加了个波浪号(~)作为前缀,它不会返回任何值,也不能带有任何参数。析构函数有助于在跳出程序(比如关闭文件、释放内存等)前释放资源。
 */
Box::~Box(){
    cout << "执行 析构函数..." << endl;
    delete ptr;
}

// 成员函数可以定义在类定义内部,或者单独使用 范围解析运算符 :: 来定义
void Box::setBreadth(double wid){
    breadth = wid;
}
double Box::getBreadth(){
    return breadth;
}

/*
 * 类的友元函数是定义在类外部,但有权访问类的所有私有(private)成员和保护(protected)成员。
 * 友元函数并不是成员函数。
 * 友元函数没有 this 指针,因为友元不是类的成员。只有成员函数才有 this 指针。
 * 友元类 = friend class ClassTwo;
 */
void printLength(Box box){
    // 友元函数直接访问 私有成员
    cout << "friend box.length=" << box.length << endl;
}

// 不能把静态成员放置在类的定义中,但是可以在类的外部通过使用范围解析运算符 :: 来重新声明静态变量从而对它进行初始化
int Box::objectCount = 1;
class OtherClass{
public:
    /*
     * C++ 内联函数是通常与类一起使用。
     * 如果一个函数是内联的,那么在编译时,编译器会把该函数的代码副本放置在每个调用该函数的地方。
     * 在类定义中的定义的函数都是内联函数,即使没有使用 inline 说明符。
     */
    inline int getSquare(int num){
        return num * num;
    }
};

/*
 * 公有继承(public):当一个类派生自公有基类时,基类的公有成员也是派生类的公有成员,基类的保护成员也是派生类的保护成员,基类的私有成员不能直接被派生类访问,但是可以通过调用基类的公有和保护成员来访问。
 * 保护继承(protected): 当一个类派生自保护基类时,基类的公有和保护成员将成为派生类的保护成员。
 * 私有继承(private):当一个类派生自私有基类时,基类的公有和保护成员将成为派生类的私有成员。
 */
// Box 子类
class SmallBox:public Box, public OtherClass{
public:
    double getArea(){
        return breadth * height;
    }
};

int main( )
{
    Box box1(6.0);      // 声明 box1,类型为 Box,执行带参数的构造函数
    box1.height = 5.0;
    box1.setBreadth(7.0);
    double volume = box1.height * box1.getLength() * box1.getBreadth();
    cout << "box.成员 calculate volume=" << volume << endl;
    cout << "box.getVolume=" << box1.getVolume() << endl;

    // 使用友元函数
    printLength(box1);

    Box box2 = box1;
    cout << "box2.getLength=" << box2.getLength() << " end."<< endl;

    Box box3(1.0);// 目的是 使用构造函数累加 objectCount
    // 静态成员在类的所有对象中是共享的
    cout << "box.static.objectCount=" << Box::objectCount << endl;

    SmallBox smallBox;
    smallBox.height=2.0;
    smallBox.setBreadth(3.0);
    smallBox.setLength(4.0);
    cout << "small box getVolume(box)=" << smallBox.getVolume() << endl;
    cout << "small box getArea(self)=" << smallBox.getArea() << endl;
    cout << "small box getSquare(OtherClass)=" << smallBox.getSquare(4) << endl;

    // 指向类的指针
    Box *ptrBox;
    // 必须在使用指针之前,对指针进行初始化。
    ptrBox = &box1;
    cout << "ptrBox.volume" << ptrBox->getVolume() << endl;

    return 0;
}

####继承、多态

#include <iostream>
using  namespace std;

// 形状
class Shape{
protected:
    double breadth;
    double height;
public:
    // 重载,函数同名,形式参数(指参数的个数、类型或者顺序)不同
    void print(int i){
        cout << "print int:" << i << endl;
    }
    void print(double d){
        cout << "print double:" << d << endl;
    }
    // 重载 + 运算符
    double operator+(const Shape &s){
        return this->height + s.height;
    }
    // 重载 ++ 运算符
    double operator++(){
        return ++height;
    }
    // 使用友元函数 重载输出
    friend ostream &operator<<( ostream &output, const Shape &s){
        output << "height : " << s.height << " breadth : " << s.breadth;
        return output;
    }

    void setHeight(double h);
    double getHeight();
    void setBreadth(double wid);

    /*
     * 虚函数
     * 多态,子类重写该方法
     * 虚函数 是在基类中使用关键字 virtual 声明的函数。
     * 在派生类中重新定义基类中定义的虚函数时,会告诉编译器不要静态链接到该函数。
     * 如果没有 virtual 关键字,子类始终执行 父类的 area,就是 静态多态,或静态链接 - 函数调用在程序执行前就准备好了。有时候这也被称为早绑定,
     */
    virtual double area(){
        cout << "执行 Shape.area" << endl;
        return 0;
    }
    /*
     * 纯虚函数(我理解就是抽象方法)
     * 您可能想要在基类中定义虚函数,以便在派生类中重新定义该函数更好地适用于对象,
     * 但是您在基类中又不能对虚函数给出有意义的实现,这个时候就会用到纯虚函数。
     */
    //virtual double area() = 0;
};

void Shape::setHeight(double h) {
    height = h;
}
double Shape::getHeight() {
    return height;
}
void Shape::setBreadth(double wid) {
    breadth = wid;
}

// 三角形
class Triangle: public Shape{
public:
    double area(){
        cout << "执行 Triangle.area" << endl;
        return (breadth * height)/2;
    }
};

// 矩形
class Rectangle: public Shape{
public:
    double area(){
        cout << "执行 Rectangle.area" << endl;
        return breadth * height;
    }
};

int main(void){
    Shape shape1;
    // 重载方法
    shape1.print(123);
    shape1.print(1.23);
    // 重载 输出运算符
    cout << "重载输出:" << shape1 << endl;
    shape1.setHeight(11);
    shape1.setBreadth(12);

    Shape shape2;
    shape2.setHeight(22);

    double height;
    // 重载 + 运算符
    height = shape1 + shape2;
    cout << "重载 + 运算符:" << height << endl;
    // 重载 ++ 运算符
    cout << "重载 ++  运算符:" << ++shape1 << endl;

    // 多态
    Shape *shape;
    Triangle triangle;
    Rectangle rectangle;

    triangle.setBreadth(11);
    triangle.setHeight(12);

    rectangle.setBreadth(22);
    rectangle.setHeight(23);

    // 编译器看的是指针的内容,而不是它的类型。
    shape = &rectangle;
    shape->area();

    shape = &triangle;
    shape->area();
}

##进阶

###文件流

标准库 fstream

  • ofstream 该数据类型表示输出文件流,用于创建文件并向文件写入信息。
  • ifstream 该数据类型表示输入文件流,用于从文件读取信息。
  • fstream 该数据类型通常表示文件流,且同时具有 ofstream 和 ifstream 两种功能,这意味着它可以创建文件,向文件写入信息,从文件读取信息。

open() 成员函数的第一参数指定要打开的文件的名称和位置,第二个参数定义文件被打开的模式。

  • ios::app 追加模式。所有写入都追加到文件末尾。
  • ios::ate 文件打开后定位到文件末尾。
  • ios::in 打开文件用于读取。
  • ios::out 打开文件用于写入。
  • ios::trunc 如果该文件已经存在,其内容将在打开文件之前被截断,即把文件长度设为 0。
#include <iostream>
#include <fstream>

using namespace std;

int main(){
    char data[100];

    ofstream outfile;
    // 以写模式打开文件
    outfile.open("testFile.txt");

    cout << "Writing to the file" << endl;
    cout << "1.Enter : ";
    // 获取输入内容
    cin.getline(data,100);

    // 向文件写入 输入的内容
    outfile << data << endl;

    cout << "2.Enter : ";
    cin >> data;
    cin.ignore();

    // 向文件写入 输入的内容
    outfile << data << endl;

    // 关闭文件
    outfile.close();

    ifstream infile;
    // 以读模式打开文件
    infile.open("testFile.txt");

    infile >> data;
    cout << "Reading from the file" << endl;
    cout << data << endl;

    infile >> data;
    cout << data << endl;

    // 关闭文件
    infile.close();
}

###异常处理

#include <iostream>
#include <exception>

using namespace std;

// 自定义异常
struct MyException: public exception{
    // what() 是异常类提供的一个公共方法,它已被所有子异常类重载。这将返回异常产生的原因。
    const char *what() const throw(){
        return "my exception";
    }
};
double division(int a,int b){
    if(b==0){
        // 抛出一个异常
        throw "Division by zero condition";
    }
    return a/b;
}
int main(){
    try{
        division(12,0);
    }catch (const char *msg){
        cerr << msg << endl;
    }

    try {
        throw  MyException();
    }catch(MyException &e){
        std::cout << e.what() << std::endl;
    }catch (std::exception &e){
        std::cout << e.what() << std::endl;
    }
    return 0;
}

###内存

#include <iostream>

using namespace std;

int main(){
    /*
     * 栈:在函数内部声明的所有变量都将占用栈内存。
     * 堆:这是程序中未使用的内存,在程序运行时可用于动态分配内存。
     */

    // 初始化为 null 的指针
    double* num = NULL;
    // 建议检查 new 运算符是否返回 NULL 指针
    // 使用 new 运算符来为任意的数据类型动态分配内存
    // new 与 malloc() 函数相比,new 不只是分配了内存,它还创建了对象。
    if( !(num = new double)){
        cout << "error out of memory";
        exit(1);
    }
    *num = 123.456;
    cout << "double is " << *num << endl;
    // 释放内存
    delete num;

    return 0;
}

###命名空间

#include <iostream>

/*
 * using 指令也可以用来指定命名空间中的特定项目。
 * 例如,如果您只打算使用 std 命名空间中的 cout 部分
 * std 命名空间中的其他项目仍然需要加上命名空间名称作为前缀
 */
using std::cout;

// 命名空间,区分不同库中相同名称的函数、类、变量等。命名空间就是定义了一个范围。
namespace firstSpace{
    void print(){
        cout << "first space print" << std::endl;
    }
}
namespace secondSpace{
    void print(){
        cout << "second space print" << std::endl;
    }
}

/*
 * 使用 using namespace 指令,在使用命名空间时就可以不用在前面加上命名空间的名称。
 * 这个指令会告诉编译器,后续的代码将使用指定的命名空间中的名称。
 */
using namespace firstSpace;

int main(){
    // 使用 using namespace 指令,在使用命名空间时就可以不用在前面加上命名空间的名称
    print();
    // 调用带有命名空间的函数或变量,需要在前面加上命名空间的名称
    secondSpace::print();
    return 0;
}

###泛型

####函数

#include <iostream>
#include <string>

using namespace std;

// 函数模板
template <typename T>
inline T const& maxObj(T const& a, T const& b){
    return a > b ? a:b;
}

int main(void){
    cout << maxObj(12,23) << endl;
    cout << maxObj("hello","world") << endl;
}

####类

#include <iostream>
#include <string>
#include <vector>
#include <cstdlib>
#include <stdexcept>

using namespace std;

// 类模板
template <class T>
class Stack{
private:
    vector<T> elems; // 元素
public:
    void push(T const&); // 入栈
    void pop(); // 出栈
    T top() const; // 返回栈 顶元素
    bool empty() const{
        // 是否为空
        return elems.empty();
    }
};

template <class T>
void Stack<T>::push(T const &elem) {
    // 追加
    elems.push_back(elem);
}

template <class T>
void Stack<T>::pop() {
    if (elems.empty()){
        throw out_of_range("Stack<>::pop() is empty");
    }
    // 删除最后一个元素
    elems.pop_back();
}

template <class T>
T Stack<T>::top() const const{
    if (elems.empty()){
        throw out_of_range("Stack<>::pop() is empty");
    }
    // 返回最后一个元素
    return elems.back();
}



int main(void){
    try{
        Stack<int> intStack;
        Stack<string> stringStack;

        intStack.push(4);
        cout << intStack.top() << endl;

        stringStack.push("hello");
        cout << stringStack.top() << std::endl;

        stringStack.pop();
        stringStack.pop();
    }catch (exception const& ex){
        cerr << "exception info = " << ex.what() << endl;
        return -1;
    }
    return 0;
}

###预处理

预处理器是一些指令,指示编译器在实际编译之前所需完成的预处理。 所有的预处理器指令都是以井号(#)开头,只有空格字符可以出现在预处理指令之前。预处理指令不是 C++ 语句,所以它们不会以分号(;)结尾。

#include <iostream>

using namespace std;

// #define 预处理指令用于创建符号常量。该符号常量通常称为宏
#define DEBUG true
// 定义一个带有参数的宏
#define MIN(a,b) ((a<b)?a: b)
// # 和 ## 预处理运算符在 C++ 和 ANSI/ISO C 中都是可用的。# 运算符会把 replacement-text 令牌转换为用引号引起来的字符串。
#define MKSTR(x) #x

// ## 运算符用于连接两个令牌。
#define CONCAT(x, y) x ## y

int main(void){
    
//条件编译
#ifdef DEBUG
    cerr << "current is debug" << endl;
#endif

// 可以使用 #if 0 语句注释掉程序的一部分
#if 0
    cout << "不进行编译的代码" << endl;
#endif

    // 带参数的宏
    cout << MIN(22,11) << endl;

    // # 运算符会把 replacement-text 令牌转换为用引号引起来的字符串。
    cout << MKSTR(HELLO C++) << endl;

    // ## 运算符用于连接两个令牌。
    cout << CONCAT(11, 22) << endl;

    // 预定义宏
    cout << "当前行号:" << __LINE__ << endl;
    cout << "当前文件名:" << __FILE__ << endl;
    cout << "当前日期:" << __DATE__ << endl;
    cout << "当前时间:" << __TIME__ << endl;

    return 0;
}

###信号处理(我的理解是swift中的通知)

#include <iostream>
#include <csignal>

using namespace std;

void signalHandler( int signum ) {
    cout << "Interrupt signal (" << signum << ") received.\n";
    exit(signum);
}

int main(void){
    /*
     * 以下 列信号可以在程序中捕获,并可以基于信号采取适当的动作。这些信号是定义在 C++ 头文件 <csignal> 中。
     * SIGABRT  程序的异常终止,如调用 abort。
     * SIGFPE   错误的算术运算,比如除以零或导致溢出的操作。
     * SIGILL   检测非法指令。
     * SIGINT   接收到交互注意信号。
     * SIGSEGV  非法访问内存。
     * SIGTERM  发送到程序的终止请求。
     */

    /*
     * signal 函数,用来捕获突发事件
     * 第一个参数是一个整数,代表了信号的编号;
     * 第二个参数是一个指向信号处理函数的指针。
     */
    signal(SIGINT,signalHandler);

    int i = 0;
    while(++i){
        if (i == 3){
            // 使用函数 raise() 生成信号
            raise(SIGINT);
        }
    }
    return 0;
}

###多线程

#include <iostream>
#include <pthread.h>

using namespace std;

#define  NUM_THREADS 5

struct ThreadData{
    int threadId;
    char *message;
};

void* sayHello(void *args){
    // 对传入的参数进行强制类型转换
    struct ThreadData *threadData;
    threadData = (struct ThreadData*) args;

    cout << "hello threadId = " << threadData->threadId ;
    cout << " message = " << threadData->message << endl;

    // 在线程完成工作后无需继续存在时 调用pthread_exit退出线程
    pthread_exit(NULL);
}

int main(void){

    // 线程的 id 变量,多个变量使用数组
    pthread_t threads[NUM_THREADS];
    struct ThreadData threadData[NUM_THREADS];
    for (int i = 0; i < NUM_THREADS; i++){
        cout << "for thread create i = " << i << endl;
        threadData[i].threadId = i;
        threadData[i].message = "this is thread message";

        /*
         * pthread_create 创建一个新的线程,并让它可执行
         *
         * thread   指向线程标识符指针。
         * attr 一个不透明的属性对象,可以被用来设置线程属性。您可以指定线程属性对象,也可以使用默认值 NULL。
         * start_routine    线程运行函数起始地址,一旦线程被创建就会执行。
         * arg  运行函数的参数。它必须通过把引用作为指针强制转换为 void 类型进行传递。如果没有传递参数,则使用 NULL。
         *
         * 通过结构传递多个参数。您可以在线程回调中传递任意的数据类型,因为它指向 void
         */
        int thread = pthread_create(&threads[i], NULL, sayHello, (void *)&(threadData[i]));
        if (thread != 0 ){
            cout << "thread create error: " << thread << endl;
            exit(-1);
        }
    }
    /*
     * pthread_exit 用于显式地退出一个线程。
     * 通常情况下,pthread_exit() 函数是在线程完成工作后无需继续存在时被调用。
     */
    pthread_exit(NULL);

    return 0;
}
#include <iostream>
#include <pthread.h>
#include <unistd.h>

using namespace std;

#define  NUM_THREADS 5

void* sayHello(void *args){
    sleep(1);
    // 对传入的参数进行强制类型转换
    int threadId = *((int *)args);
    cout << "hello thread id = " << threadId << endl;

    // 在线程完成工作后无需继续存在时 调用pthread_exit退出线程
    pthread_exit(NULL);
}

int main(void){

    pthread_t threads[NUM_THREADS];
    pthread_attr_t attr;
    void *status;

    // 初始化并设置线程为可连接的(joinable)
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

    for (int i = 0; i< NUM_THREADS; i++){
        cout << "for create thread = " << i << endl;
        int thread = pthread_create(&threads[i], NULL, sayHello, (void *)&i);
        if (thread){
            cout << "for create thread error = " << thread << endl;
            exit(-1);
        }
    }

    // 删除属性
    pthread_attr_destroy(&attr);
    for (int i = 0 ; i< NUM_THREADS; i++){
        /*
         * pthread_join() 子程序阻碍调用程序,直到指定的 threadid 线程终止为止。
         * 当创建一个线程时,它的某个属性会定义它是否是可连接的(joinable)或可分离的(detached)。
         * 只有创建时定义为可连接的线程才可以被连接。如果线程创建时被定义为可分离的,则它永远也不能被连接。
         * 使用 pthread_join() 函数来等待线程的完成
         */
        int thread = pthread_join(threads[i], &status);
        if (thread){
            cout << "error unable join = " << thread << endl;
            exit(-1);
        }
        cout << "for completed thread = " << i;
        cout << " exiting with status = " << status << endl;
    }
    cout << "main completed" << endl;
    return 0;
}

###CGI

未整理

###标准库

C++ 标准库包含了所有的 C 标准库,为了支持类型安全,做了一定的添加和修改。

####标准函数库

这个库是由通用的、独立的、不属于任何类的函数组成的。函数库继承自 C 语言。

  • 输入/输出 I/O
  • 字符串和字符处理
  • 数学
  • 时间、日期和本地化
  • 动态分配
  • 其他
  • 宽字符函数

####面向对象类库

这个库是类及其相关函数的集合。

  • 标准的 C++ I/O 类
  • String 类
  • 数值类
  • STL 容器类
  • STL 算法
  • STL 函数对象
  • STL 迭代器
  • STL 分配器
  • 本地化库
  • 异常处理类
  • 杂项支持库

##个人补充

###->.

-> 前面是指针,. 前面是变量

###域运算符 ::

  • 不能把静态成员放置在类的定义中,但是可以在类的外部通过使用 范围解析运算符 :: 来重新声明静态变量从而对它进行初始化,
  • 成员函数可以定义在类定义内部,或者在类外单独使用 范围解析运算符 :: 来定义
  • 如果有个局部变量与全局变量同名 ::a 可以使用全局变量
  • :: 只能访问静态成员函数
  • std::cout 表示 cout 是在 std 中的变量
  • using std::cout 只使用 std 命名空间中的 cout 部分 std 命名空间中的其他项目仍然需要加上命名空间名称作为前缀,如 std::endl
  • :: 左边一定是类名/命名空间,右边一定是变量名/函数名,左侧没有东西的时候,代表右侧的函数/变量是全局的

###*指针 和 &引用

  • & 在定义变量的时候是引用,起标识作用,如 int &a = b; a为b的一个引用, 引用声明完毕后,相当于目标变量名有两个名称,即该目标原名称和引用名。 声明一个引用,不是新定义了一个变量,它本身不是一种数据类型,因此引用本身不占存储单元,系统也不给引用分配存储单元。 不能建立数组的引用
  • & 在表达式中为取地址,你的地址可以是任何类型 如 int *a = &b; a为指向b整型的一个指针
  • * 是指针,是取地址的内容

###include ""include <>

引号会先在程序所在的路径里找(自定义的库函数) 尖括号是从系统的头文件开始找(标准库函数)


有问题的地方,希望大家指出

转载于:https://my.oschina.net/asjoker/blog/847748

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值