c++中的常用知识点总结

命名空间

使用命名空间之后,调用代码时可以省去也可以不省去相关的前缀。

#include 

using namespace std;//使用c++自己的命名空间
int main() {
    int num1 = 10;

    std::cout << "Hello, World!" << std::endl;
    cout<<num1<<endl;
    return 0;
}

自定义命名空间

// 命名空间

#include 

// 声明std,我们的main函数就可以直接使用里面的成员,不需要使用 std::
using namespace std; // C++自己的命名空间 (C# .net 命名空间)

// 自定义命名空间
namespace derry1 {
    int age = 33;
    char * name = "Derry猛男1";

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

    void action() {
        cout << "derry1 action" << endl;
    }
}

// TODO ------ 命名空间里面重复的函数
// 自定义命名空间
namespace derry2 {
    void action() {
        cout << "derry2 action" << endl;
    }
}

// TODO ------ 小概率会遇到的情况,命名空间的嵌套
// 自定义命名空间
namespace derry3 {
    namespace derry3Inner {
        namespace derry3Inner1 {
            namespace derry3Inner2 {
                namespace derry3Inner3 {
                    void out() {
                        cout << "爱恨情仇人消瘦,悲欢起落人寂寞" << endl;
                    }
                }
            }
        }
    }
}

// 声明各个写的 命名空间
// using namespace derry1;

int main() {
    cout << "命名空间" << endl;

    // 声明各个写的 命名空间
    using namespace derry1;

    int ageValue = derry1::age; // 方式1 使用 刚刚声明的命名空间
    derry1::show(); // 使用 刚刚声明的命名空间

    ageValue = age; // 方式2 直接去引出来 ::
    show(); // 直接去引出来 ::


    // TODO ------ 命名空间里面重复的函数
    using namespace derry2;
    // action(); 很尴尬
    derry1::action();
    derry2::action();

    // TODO ------ 小概率会遇到的情况,命名空间的嵌套

    // 第一种方式 先声明命名空间  再使用
    using namespace derry3::derry3Inner::derry3Inner1::derry3Inner2::derry3Inner3;
    // 再使用
    out();

    // 第二种方式 直接使用
    derry3::derry3Inner::derry3Inner1::derry3Inner2::derry3Inner3::out();

    return 0;
}


  • 头文件:Student.h
//
// Created by sunteng on 2023/9/5.
//

#ifndef TEST_STUDENT_H
#define TEST_STUDENT_H

#endif //TEST_STUDENT_H

class Student{

private:
    //下面的成员和函数,都是私有
    char * name;
    int age;

public:
    //下面的成员和函数,都是公有
    void setAge(int age);
    void setName(char *name);
    int getAge();
    char * getName();

};
  • 类文件:Student.cpp
//
// Created by sunteng on 2023/9/5.
//


#include "Student.h"

// 根据 Student.h 头文件 ,写实现

// 和实现头文件那个函数,没有任何关系,相当于另外一个函数
/*void setAge(int age) {

}*/

void Student::setAge(int age) {
    //this是一个Student类型的指针
    this->age = age;
}

void Student::setName(char *name) {
    this->name = name;
}

int Student::getAge() {
    return this->age;
}

char * Student::getName() {
    return this->name;
}
  • main
#include 
#include "Student.h"//引入头文件即可
using namespace std;
int main() {

    Student student1;//栈区开辟空间

    //赋值
    student1.setName("brett");
    student1.setAge(19);

    cout<<"name:"<<student1.getName()<<" ,age:"<<student1.getAge()<<endl;

    Student* student2 = new Student();//new 堆区分配空间

    student2->setAge(88);
    student2->setName("mike");

    cout<<"name:"<<student2->getName()<<" ,age:"<<student2->getAge()<<endl;


    //堆区分配的对象使用完之后必须手动释放
    if(student2){
        delete student2;
        student2 = NULL;
    }
    // new/delete 是一套  会调用构造函数 与 析构函数   【C++标准规范】
    // malloc/free是一套  不调用构造函数 与 析构函数 【C的范畴,虽然不推荐,但是也是可以的】


    return 0;
}

  • 构造函数和析构函数

#include 
#include 
using namespace std;

class Student {

// 构造函数
public:
    // 空参数构造函数
    Student() {
        cout << "空参数构造函数" << endl;
    }

    // 一个参数的构造函数
    // :Student(name, 87) 等价 1.调用两个参数的构造函数, 2.再调用当前函数
    // 学生说的:先调用两个参数的,再调用一个的
    Student(char *name) :Student(name, 87) {
        cout << "一个参数的构造函数" << endl;
        if(!this->name){//防止重复赋值
            this->name = name;
        }

    }

    // 两个参数的构造函数
    Student(char *name, int age) {
        // this->name = name;

        // 堆区
        this->name = (char *) (malloc(sizeof(char *) * 10));
        strcpy(this->name, name);

        this->age = age;
        cout << "两个参数的构造函数" << endl;
    }

    // 析构函数 Student对象的,临终遗言,Student对象被回收了,你做一些释放工作
    // delete stu 的时候,我们的析构函数一定执行
    // free不会执行析构函数,也意味着,你没法在析构函数里面,做释放工作, malloc也不会调用构造函数
    ~Student() {
        cout << "析构函数" << endl;

        // 必须释放 堆区开辟的成员
        if (this->name) {
            free(this->name);
            this->name = NULL; // 执行NULL的地址,避免出现悬空指针
        }
    }

// 私有属性
private:
    char *name;
    int age;

// 公开的 set get 函数
public:
    int getAge() {
        return this->age;
    }

    char *getName() {
        return this->name;
    }

    void setAge(int age) {
        this->age = age;
    }

    void setName(char *name) {
        this->name = name;
    }
};

int main() {


    // TODO =========== 下面是堆区 开辟空间的  堆区必须手动释放,否则内存占用越来

    // 系统源码中,会看到,很多使用 new 关键字

    // *stu  ->:调用一级指针的成员
    // new/delete
    // C++中,必须使用 new/delete 一套
    Student *stu = new Student("杜子腾");
    cout << "name:" << stu->getName() << ", age:" << stu->getAge() <<  endl;
    delete stu;


    return 0;
}

  • 拷贝构造函数与构造函数
// 4.拷贝构造函数。

#include 
#include 

using namespace std;

class Student {

public:
    Student() { cout << "空参数构造函数" << endl; }

    // 两个参数的构造函数
    Student(char *name, int age) : name(name), age(age) {
        cout << "两个参数构造函数" << endl;
    }

    // 析构函数
    // ~Student(char * name) { } 这样写,就不是析构函数了,如果你这样写,C/C++编译器对你很无语
    ~Student() {
        cout << "析构函数" << endl;
    }

    // 拷贝构造函数,它默认有,我们看不到,一旦我们写拷贝构造函数,会覆盖她
    // 对象1 = 对象2
    // 覆盖拷贝构造函数
    Student(const Student & student) { // 常量引用:只读的,不让你修改
        cout << "拷贝构造函数" << endl;

        // 我们自己赋值
        // 为什么要自己赋值,自己来控制,就可以 例如:-10
        this->name = student.name;
        this->age = student.age - 10;

        cout << "自定义拷贝构造函数 内存地址 " << &student << endl;
    }

// 私有属性
private:
    char *name;
    int age;

// 公开的 set get 函数
public:
    int getAge() {
        return this->age;
    }

    char *getName() {
        return this->name;
    }

    void setAge(int age) {
        this->age = age;
    }

    void setName(char *name) {
        this->name = name;
    }
};

struct Person {
    int age;
    char *name;
};

// TODO = 号的意义 隐士代码,引出 拷贝构造函数

int main() {
    Person person1 = {100, "张三丰"};

    // = 你看起来,没有什么特殊,隐士的代码:你看不到  C/C++编译器 会把p1的成员值赋值给p2成员
    Person person2 = person1;

    cout << &person1 << endl;
    cout << &person2 << endl;

    cout << person2.name << ",  " << person2.age << endl;

    // 思考:对象 对象1=对象2  默认的 拷贝构造函数

    return 0;
}

// TODO  拷贝构造函数

/*int main() {
    Student stu1("李鬼", 34);
    Student stu2 = stu1;

    cout << stu2.getName() << " , " <<  stu2.getAge() <<  endl;
    cout << "main " << &stu1 << endl; // 地址的打印是一样的,  注意:cnetos的环境 地址打印有差异,要注意



    // TODO  拷贝构造函数的注意点:
    // Student stu1("李鬼", 34);

    // Student stu2;
    // stu2 = stu1; // 这样赋值是不会调用 自定义拷贝构造函数,但是会调用默认赋值
    // Student stu2 = stu1;  // 这样赋值是会调用 自定义拷贝构造函数,我们自己赋值

    // cout << stu2.getName() << " , " <<  stu2.getAge() <<  endl;

    getchar(); // 程序等待在这一行

    return 0;
} // main函数弹,stu1栈成员会回收  stu2栈成员会回收
*/

// TODO 这种写法 拷贝构造函数  到底会不会调用
/*int main() {
    Student *student1 = new Student("杜子腾", 39);

    Student *student2 = student1;  // 压根就不会执行拷贝构造函数(指针指向问题,和我们刚刚那个  对象2=对象1 是两回事)

    student2->setAge(99);

    cout << student1->getName() << student1->getAge() << endl;

    return 0;
}*/

  • 深拷贝与浅拷贝
#define _CRT_SECURE_NO_WARNINGS // strcpy运行会报错,支持

#include
#include
using namespace std;

class Student
{
public:

    int age;
    char * name;

    Student() { cout << "空参数构造函数" << endl; }

    Student(char * name) :Student(name, 99) {
        cout << "一个参数构造函数 this:" << this << endl;
    }

    Student(char * name, int age) {
        cout << "二个参数构造函数 this:" << this << endl;

        this->name = (char *)malloc(sizeof(char *)* 10);
        strcpy(this->name, name);

        this->age = age;
    }

    ~Student() {
        cout << "析构函数执行 &this->name:" << this->name << endl;

        free(this->name);
        this->name = NULL;
    }

    // 默认有一个拷贝构造函数 隐士的 我们看不见
    // 一旦复写了拷贝构造函数,默认的还在吗? Java的构造函数一个思路
    // 自定义拷贝构造函数 如果有堆成员,必须采用深拷贝
    Student(const Student & stu) {
        // stu 旧地址

        // this 新地址

        // s2 = 新地址

        cout << "拷贝构造函数 &stu:" << &stu << " this:" << this << endl;//二者地址不一样

        // 【浅拷贝】:新地址name  旧地址name 指向同一个空间,会造成,重复free的问题,引发奔溃
        // 新地址name = 旧地址 (浅拷贝)
        // this->name = stu.name;

        // 【深拷贝】
        this->name = (char *)malloc(sizeof(char *)* 10);
        strcpy(this->name, name);

        this->age = stu.age;

        cout << "拷贝构造函数2 this->name:" << (this->name) << "  stu.name:" << stu.name << endl;

        // 深拷贝 后面见  原理全部打通的时候讲
    } // 此拷贝构造函数执行完 旧会出现一个 this==新地址  给 main函数的 stu


    // 默认的拷贝构造函数 是浅拷贝
};

void showStudent(Student stu) {
    cout << "showStudent函数:" << &stu << "  " << stu.name << "," << stu.age<< endl;
}

int main() {
    Student stu("刘奋", 31);

    showStudent(stu); // 弹栈后 新地址name释放一遍
    showStudent(stu);
//
//    showStudent(stu);
//
//
//    showStudent(stu);
//
//
//    showStudent(stu);

    getchar();
    return 0;
} // main函数弹栈 stu 旧地址

指针常量 常量指针 常量指针常量

// 指针常量 常量指针 常量指针常量

#include 
#include 
#include 

using namespace std;

int main() {

    // *strcpy (char *__restrict, const char *__restrict);
    // strcpy()


    int number = 9;
    int number2 = 8;

    // 大道至简 一分钟搞定

    // 常量指针
    const int * numberP1 = &number;
    // *numberP1 = 100; // 报错,不允许去修改【常量指针】存放地址所对应的值
    // numberP1 = &number2; // OK,允许重新指向【常量指针】存放的地址

    //  指针常量
    int* const numberP2 = &number;
    *numberP2 = 100; // OK,允许去修改【指针常量】存放地址所对应的值
    // numberP2 = &number2; // 报错,不允许重新指向【指针常量】存放的地址

    // 常量指针常量
    const int * const numberP3 = &number;
    // *numberP3 = 100; // 报错,不允许去修改【常量指针常量】存放地址所对应的值
    // numberP3 = &number2; // 报错,不允许重新指向【常量指针常量】存放的地址

    return 0;
}

运算符重载

// 2.类里运算符重载。

#include 
using namespace std;

class Derry {
private:
    int x,y;

public:
    Derry() {

    }

    // 系统C++源码,大量使用此方式 :x(x), y(y)
    Derry(int x, int y) :x(x), y(y) {}

    // set get 函数
    void setX(int x) {
        this->x = x;
    }
    void setY(int y) {
        this->y = y;
    }
    int getX() {
        // this->x  -9; 系统怕你在函数里面 修改了
        return this->x;
    }
    int getY() {
        return this->y;
    }

    // +号,运算符重载
    /*Derry operator + (Derry derry1) {
        // this指针 指向当前对象,所以只需要一个
        int x = this->x + derry1.getX();
        int y = this->y + derry1.getY();
        return Derry(x, y);
    }*/

    // 系统是这样写的  常量引用:不允许修改,只读模式
    // const 关键字的解释
    // & 性能的提高,如果没有&  运行+ 构建新的副本,会浪费性能
    // 如果增加了& 引用是给这块内存空间取一个别名而已
    Derry operator + (const Derry& derry1) {
        // this指针 指向当前对象,所以只需要一个
        int x = this->x + derry1.x; // 我在类的里面,是可以拿私有成员的
        int y = this->y + derry1.y; // 我在类的里面,是可以拿私有成员的
        return Derry(x, y);
    }

    // 运算符- 重载
    Derry operator - (const Derry & derry1) {
        int x = this->x - derry1.x;
        int y = this->y - derry1.y;
        return Derry(x, y);
    }
};

int main() {
    Derry derry1(1000, 2000);
    Derry derry2(3000, 4000);

    // Derry result = derry1 + derry2;

     Derry result = derry2 - derry1;

    cout << result.getX() << " , " << result.getY() << endl;

    return 0;
}

二义性与虚基类

// 多继承 二义性2:
// 在真实开发过程中,严格避免出现 二义性

#include 

using namespace std;

// 祖父类
class Object {
public:
    int number;
};

// 父类1
class BaseActivity1 : public Object {

};

// 父类2
class BaseActivity2 : public Object {

};

// 子类
class Son : public BaseActivity1, public BaseActivity2 {

    // 第二种解决方案: 在类中定义同名成员,覆盖掉父类的相关成员
public:
    int number;

};


int main() {
    Son son;

    // error: request for member 'show' is ambiguous  二义性 歧义
    // son.number = 2000;

    // 第一种解决方案: :: 明确指定
    son.BaseActivity1::number  = 1000;
    son.BaseActivity2::number  = 1000;

    // 第二种解决方案: 在类中定义同名成员,覆盖掉父类的相关成员
    son.number = 3000;

    // 第三种解决方案: 【虚基类】 属于 虚继承的范畴

    return 0;
}

//第三种方式;虚基类

// 第三种解决方案: 【虚基类】 属于 虚继承的范畴
// 真实C++开始,是很少出现,二义性(歧义) 如果出现, 系统源码(系统用 第三种解决方案)

#include 

using namespace std;

// 祖父类
class Object{
public:
    int number;
    void show() {
        cout << "Object show run..." << endl;
    }
};

// 父类1
class BaseActivity1 : virtual public Object {
};

// 父类2
class BaseActivity2 : virtual public Object {
};

// 子类
class Son : public BaseActivity1, public BaseActivity2 {

};

int main() {
    Object object;
    BaseActivity1 baseActivity1;
    BaseActivity2 baseActivity2;
    Son son;

    object.number = 100;
    baseActivity1.number = 200;
    baseActivity2.number = 300;
    son.number = 400;

    object.show();
    baseActivity1.show();
    baseActivity2.show();
    son.show();

    cout << object.number << endl;
    cout << baseActivity1.number << endl;
    cout << baseActivity2.number << endl;
    cout << son.number << endl;

    return 0;
}
  • 虚基类

在C++中,虚基类是用于解决多继承中的菱形继承问题的一种机制。菱形继承指的是一个派生类同时继承自两个或多个基类,而这些基类又共同继承自同一个基类,形成了一个菱形的继承结构。

虚基类的作用是解决菱形继承带来的二义性和冗余的问题。当一个派生类通过多条路径继承自同一个基类时,如果不使用虚基类,那么在派生类中就会存在多个基类子对象的实例,这样就会导致同名成员在派生类中出现冗余,访问这些成员时会产生二义性。

通过使用虚基类,可以确保在派生类中只有一个基类子对象的实例,从而避免了冗余和二义性。虚基类的成员在派生类中只有一份拷贝,这样就可以确保派生类对基类成员的访问是唯一的。

使用虚基类的语法是在派生类的基类列表中,将虚基类声明为虚基类。例如:

class Base {
public:
    // Base类的成员
};

class Derived1 : virtual public Base {
public:
    // Derived1类的成员
};

class Derived2 : virtual public Base {
public:
    // Derived2类的成员
};

class Derived3 : public Derived1, public Derived2 {
public:
    // Derived3类的成员
};

在上面的例子中,Base是虚基类,Derived1和Derived2都通过虚继承方式继承自Base。Derived3通过多继承同时继承自Derived1和Derived2,这样就避免了菱形继承带来的问题。

总结来说,虚基类的作用是解决多继承中的菱形继承问题,避免冗余和二义性,确保派生类对基类成员的访问是唯一的。

公有继承与私有继承


#include 

using namespace std;

class Person {
public:
    char *name;
    int age;

public:
    Person(char *name, int age) : name(name) {
        this->age = age;
        cout << "Person 构造函数" << endl;
    }

    void print() {
        cout << this->name << " , " << this->age << endl;
    }
};

// 1.默认是 隐式代码: : private Person
// 2.私有继承:在子类里面是可以访问父类的成员,但是在类的外面不行
// 3.必须公开继承,才可以访问父类的成员
class Student : public Person {

// 类 默认是私有,注意下

private:
    char * course;

public:
    // :父类 , 给自己子类成员初始化
    Student(char * name, int age, char* course) : Person(name, age) , course(course) {
        cout << "Student 构造函数" << endl;
    }

    void test() {
        cout << name << endl;
        cout << age << endl;
        print();
    }
};

int main() {
    Student stu("李元霸", 99, "C++");

    // 公开继承,才可以拿父类的成员
    stu.name = "李四";
    return 0;
}

静态类

// 2.C++static关键字。 正确的写法

/**
 * 静态的总结:
 * 1.可以直接通过类名::静态成员(字段/函数)
 * 2.静态的属性必须要初始化,然后再实现(规则)
 * 3.静态的函数只能取操作静态的属性和方法
 */

#include 

using namespace std;

class Dog {
public:
    char * info;
    int age;

    // 先声明
    static int id;

    static void update() {
        id += 100;

        // 报错:静态函数不能调用非静态函数
        // update2();
    }

    void update2() {
        id = 13;
    }
};

// 再实现
int Dog::id = 9;

int main() {
    Dog dog;
    dog.update2(); // 普通函数
    Dog::update(); // 静态函数
    dog.update(); // 对象名.静态函数(一般都是使用::调用静态成员,这种方式可以 知道就行)

    cout << Dog::id << endl;
    return 0;
}

友元类和友元函数

在C++中,友元类和友元函数是一种特殊的访问权限控制机制,允许一个类或函数访问另一个类的私有成员。

友元类(Friend Class)是指在一个类中声明另一个类为友元,从而使得被声明的类可以访问声明它为友元的类的私有成员。友元类的声明通常出现在类的定义中,例如:

class A {
    friend class B; // B是A的友元类
private:
    int privateData;
};

class B {
public:
    void accessPrivateData(A& obj) {
        int data = obj.privateData; // 可以访问A类的私有成员
    }
};

在上面的例子中,类B被声明为类A的友元类,因此类B可以访问类A的私有成员privateData。

友元函数(Friend Function)是指在一个类中声明一个函数为友元,从而使得被声明的函数可以访问声明它为友元的类的私有成员。友元函数的声明通常出现在类的定义中,例如:

class A {
    friend void printPrivateData(A& obj); // printPrivateData是A的友元函数
private:
    int privateData;
};

void printPrivateData(A& obj) {
    int data = obj.privateData; // 可以访问A类的私有成员
}

在上面的例子中,函数printPrivateData被声明为类A的友元函数,因此函数printPrivateData可以访问类A的私有成员privateData。

需要注意的是,友元类和友元函数破坏了封装性,因此应该谨慎使用。过度使用友元可能会导致代码的可维护性和可读性下降。在设计类的时候,应该优先考虑使用成员函数和访问修饰符(如public、private、protected)来实现对类成员的访问控制。只有在确实需要访问私有成员的特殊情况下,才考虑使用友元类或友元函数。

// 友元函数

// 老外:你是它的好朋友,那就可以拿私有成员给好朋友

#include 

using namespace std;

class Person {
private: // 私有的age,外界不能访问
    int age = 0;

public:
    Person(int age) {
        this->age = age;
    }

    int getAge() {
        return this->age;
    }

    // 定义友元函数 (声明,没有实现)
    friend void updateAge(Person * person, int age);
};

// 友元函数的实现,可以访问所以私有成员
void updateAge(Person* person, int age) {
    // 默认情况下:不能修改 私有的age
    // 谁有这个权限:友元(拿到所有私有成员)
    person->age = age;
}

int main() {
    Person person = Person(9);
    updateAge(&person, 88);

    cout << person.getAge() << endl;
    return 0;
}

可变参数

#include 
#include  // 可变参数的支持
using namespace std;

// Java的可变参数: int ...
// C++的可变参数写法:...

// count变量的第二个用处,用于循环遍历长度
void sum(int count, ...) {
    va_list vp; // 可变参数的动作

    // 参数一:可变参数开始的动作vp
    // 参数二:内部需要一个 存储地址用的参考值,如果没有第二个参数,内部他无法处理存放参数信息
    va_start(vp, count);

    // 到这里后:vp就已经有丰富的信息

    for (int i = 0; i < count; ++i) {
        int r = va_arg(vp, int);
        cout << r << endl;
    }

    // 越界 系统值 乱码
    // 取出可变参数的一个值 【娶不到后,会取系统值 乱码】
//   int number  = va_arg(vp, int);
//    cout << number << endl;

    // 关闭阶段(规范:例如:file文件一样 要关闭)
    va_end(vp);
}

// 1.可变参数
int main() {

    sum(3, 6,7,8); // 真实开发过程的写法

    return 0;
}

this是什么——指针常量

class Worker {
public:
    char * name;
    int age = NULL; // C++中不像Java,Java有默认值, 如果你不给默认值,那么就是系统值 -64664

    // int * const  指针常量 指针常量【地址对应的值能改,地址不可以修改】
    // const int *  常量指针 常量指针【地址可以修改,地址对应的值不能改】

    // 纠结:原理:为什么可以修改age
    // 默认持有隐士的this【类型 * const this】
    // 类型 * const 指针常量:代表指针地址不能被修改,但是指针地址的值是可以修改的
    void change1() {
        // 代表指针地址不能被修改
        // this = 0x6546;  // 编译不通过,地址不能被修改,因为是指针常量
        // 地址不可以修改
        // this = 0x43563;

        // 隐士的this
        // 但是指针地址的值是可以修改的
        // 地址对应的值能改
        this->age = 100;
        this->name = "JJJ";
    }

    // 默认现在:this 等价于 const Student * const  常量指针常量(地址不能改,地址对应的值不能改)
    void changeAction() const {
        // 地址不能改
        // this = 0x43563;

        // 地址对应的值不能改
        // this->age = 100;
    }

    // 原理:修改隐士代码  const 类型 * const 常量指针常量
    void showInfo() const {
        // this->name = "";
        // this->age = 88;

        // 只读的
        cout << "age:" << age << endl;
    }
};

多线程

C++ 11 之后添加了新的标准线程库 std::thread,std::thread 在 头文件中声明,因此使用 std::thread 时需要包含 在 头文件。

// 演示多线程的CPP程序
// 使用三个不同的可调用对象
#include 
#include 
using namespace std;

// 一个虚拟函数
void foo(int Z)
{
      for (int i = 0; i < Z; i++) {
            cout << "线程使用函数指针作为可调用参数\n";
          }
}

// 可调用对象
class thread_obj {
public:
      void operator()(int x)
      {
            for (int i = 0; i < x; i++)
              cout << "线程使用函数对象作为可调用参数\n";
          }
};

int main()
{
      cout << "线程 1 、2 、3 "
        "独立运行" << endl;
    
      // 函数指针
      thread th1(foo, 3);//不需要显式调用start()方法来启动线程,std::thread对象的构造函数会自动启动线程的执行。
    
      // 函数对象
      thread th2(thread_obj(), 3);
    
      // 定义 Lambda 表达式
      auto f = [](int x) {
            for (int i = 0; i < x; i++)
              cout << "线程使用 lambda 表达式作为可调用参数\n";
          };
    
      // 线程通过使用 lambda 表达式作为可调用的参数
      thread th3(f, 3);
    
      // 等待线程完成
      // 等待线程 t1 完成
      th1.join();
    
      // 等待线程 t2 完成
      th2.join();
    
      // 等待线程 t3 完成
      th3.join();
    
      return 0;
}

/*
线程 1 、2 、3 独立运行
线程使用函数指针作为可调用参数
线程使用函数指针作为可调用参数
线程使用函数指针作为可调用参数
线程使用函数对象作为可调用参数
线程使用函数对象作为可调用参数
线程使用函数对象作为可调用参数
线程使用 lambda 表达式作为可调用参数
线程使用 lambda 表达式作为可调用参数
线程使用 lambda 表达式作为可调用参数
*/

你可能感兴趣的:(ndk,c++,算法,开发语言)