c++构造/拷贝构造函数初始化变量*

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

class Person {
   public:
    int id;
    string name;

   public:
    Person() {
        this->id = 200;
        cout << "None param constructor" << endl;
    }

    /* explicit */ Person(int id) {
        cout << "One param constructor" << endl;
        this->id = id;
    }

    Person(int id, string name) {
        this->id = id;
        this->name = name;
        cout << "Two params constructor" << endl;
    }

    // 如果参数不加const, 这种Person pp4 = Person(1, "qiumc");写法会报错,因为Person(1, "qiumc")产生一个临时右值,
    // 临时右值在通过copy构造函数赋值给左值(copy构造函数的参数)的时候,不能赋值给非const的左值。
    Person(const Person& p) {
        this->id = p.id;
        this->name = p.name;
        cout << "copy constructor" << endl;
    }

    Person(Person&& p) {
        this->id = p.id;
        this->name = p.name;
        cout << "move constructor" << endl;
    }

};

/**
 * @brief
 * 整形初始化的几种方式
 */
void TestIntInit() {
    // case1
    int i1 = 100;

    // case2
    int i2(100);
    int i3{100};

    // case3
    int i4 = int(100);
    int i5 = int{100};

    // case4
    int i6 = {100};
}

/**
 * @brief
 * 有参构造函数的几种写法
 */
void TestPersonParamInit() {
    // case1
    // 这里发生了隐式转换,如果在单个参数构造函数前,加上explicit,将禁止这种隐式转化
    // 会先将1000隐士转化为Person(1000)临时对象,再将该临时对象调用copy构造函数,完成
    // 向pp1的赋值
    Person pp1 = 1000;

    // case2
    // 直接调用了两个参数的构造函数
    Person pp2(1, "qiumc");
    Person pp3{1, "qiumc"};

    // case3
    // 产生了临时对象Person(1, "qiumc"),然后将该临时对象调用copy构造函数赋值给pp4
    // 临时对象Person(1, "qiumc")是一个右值,而移动构造函数的参数类型是一个右值类型,所以,如果有移动构造函数,
    // 这种形式将会调用移动构造函数,没有移动构造函数,将会调用copy构造函数
    Person pp4 = Person(1, "qiumc");
    // 同上
    Person pp5 = Person{1, "qimmc"};

    // case4
    // 这种方式直接调用了两个参数的构造函数,而没有调用拷贝构造函数
    // 如果有移动构造函数,也不会调用移动构造函数
    // 这种形式也是一种单参数类型的隐式转化,如果两个参数的构造函数被声明为explicit形式,则这种定义将会报错
    Person pp6 = {1, "qiumc"};

    cout << pp1.id << " " << pp2.id << " " << pp3.id << " " << pp4.id << " " << pp5.id << " " << pp6.id << endl;
}

/**
 * @brief
 * 无参构造函数的几种写法
 */
void TestPersonInit() {
    // 不能写成Person p1();因为这里无法和函数声明相区分开
    // 同上case2
    Person p2;
    Person p3{};

    // 同上case3,下面这两种,可以使用移动构造函数来减少拷贝
    Person p4 = Person();
    Person p5 = Person{};

    // 同上case4
    Person p6 = {};

}

/**
 * @brief
 * 一个参数的构造函数的简写方式
 */
void TestPersonSingleParamInit() {
    // 如果没有类型符合的单参构造函数,这四种写法都会报错
    // 下面这些都是发生了隐式转化
    // 构造函数被声明为explicit时候,会禁止所有当前自定义的隐式类型转换,所以如果explicit修饰构造函数后,下面变量的定义都会报错
    // explicit ,当有一个构造函数的定义和声明的时候,只能出现在构造函数声明处,不能出现在构造函数的定义处
    Person p1 = 100;           // id = 100
    Person p2 = (200);         // id = 200
    Person p3 = (1, 2, 3, 4);  // id = 4

    Person p4 = {1};  //这种形式也是一种单参数类型的隐式转化,但是这种转换并没有产生临时对象后再调用copy构造函数
    cout << p1.id << ":" << p2.id << ":" << p3.id << endl;
}

/**
 * @brief
 * 拷贝构造函数的几种写法
 */
void TestPersonCopy() {
    // 调用构造函数
    Person pp(1, "qiumc");

    // 调用拷贝构造函数
    Person pp1(pp);
    // 调用拷贝构造函数
    Person pp2{pp};

    // 第二次调用:如果如果有移动构造函数先调用移动构造函数,否则调用copy构造函数
    // 调用拷贝构造函数后,调用拷贝/移动构造函数
    Person pp3 = Person(pp);
    // 调用拷贝构造函数后,调用拷贝/移动构造函数
    Person pp4 = Person{pp};

    // 发生了隐式类型转换,但仅仅调用拷贝构造函数
    Person pp5 = {pp};

}

/**
 * @brief
 * 注意整型数据初始化,和自定义类型初始化,基本上是可以类比的。
 */
int main(int argc, char const* argv[]) { TestPersonCopy(); }
posted @ 2021-11-07 10:10  邱明成  阅读(163)  评论(0编辑  收藏  举报