Skip to content

构造函数

说明

explicit

  • 默认构造函数一般需要加上,防止隐式转换
  • 拷贝构造函数和移动构造函数一般不需要,它们就是要进行同类转换

列表初始化

  • 推荐使用列表初始化,更加简洁且可以解决一些问题(如引用属性初始化)
  • 无法使用时再考虑传统的初始化

const

  • 靠近谁就修饰谁,使其只读,函数参数一般添加,防止修改原对象
  • 构造时类有引用属性不需要添加

noexcept

  • 不要向外抛出异常,可以提高性能
  • 移动构造函数移动赋值运算符和交换函数标记为 noexcept

默认构造函数

  • 无参或所有参数都有默认值的构造函数。
  • 一般情况(无引用属性,无指针属性)使用default默认生成(无默认值),否则需要自己初始化
cpp
#include <iostream>

class Student
{
public:
    explicit Student() = default;

private:
    std::string name;
    int age;
};
cpp
#include <iostream>

class Student
{
public:
    explicit Student(int age, const std::string &name) : age(age), name(name) {}

private:
    std::string name;
    int age;
};

拷贝构造函数

同类型对象创建新对象的构造函数

cpp
#include <iostream>

class Student
{
public:
    // 默认构造
    explicit Student() = default;

    // 拷贝构造
    Student(const Student &other) : name(other.name), age(other.age) {}

private:
    std::string name;
    int age;
};

int main()
{
    Student s1;

    // 两种方式都是调用拷贝构造
    Student s2(s1);
    Student s3 = s1;
    return 0;
}

移动拷贝构造

参数是类的右值引用

cpp
#include <iostream>

class Student
{
public:
    // 默认构造
    explicit Student() = default;

    // 移动构造(std::move为了避免string对象深拷贝效率低,不使用和age一样直接赋值也不会报错)
    Student(Student &&stu) noexcept : name(std::move(stu.name)), age(stu.age) {}

private:
    std::string name;
    int age;
};

int main()
{
    Student s1;

    // 两种方式都是在调用移动构造函数来初始化对象
    Student s2(std::move(s1));
    Student s3 = std::move(s1);
    return 0;
}

含引用属性

  1. 只适合用于单个对象,如配置类只需要一个
  2. 必须在构造函数使用列表初始化
cpp
#include <iostream>

class Student
{
public:
    // 默认构造
    explicit Student(std::string &name, int age) : name(name), age(age) {}

    // 拷贝构造
    Student(const Student &other) : name(other.name), age(other.age) {}

private:
    // 必须在构造函数初始化,并且使用列表初始化
    // 无论是否动态,多个对象都会共享同一个name,因此只适合单个对象的情况,如配置类
    std::string &name;
    int age;
};

int main()
{
    std::string name = "Jerry";
    Student s1(name, 18);
    return 0;
}

规则

  • Rule of Zero:如果不需要自定义析构函数、拷贝/移动操作,全部不定义
  • Rule of Three:如果需要自定义析构函数,也应该自定义拷贝构造和拷贝赋值
  • Rule of Five (C++11):如果需要自定义任何一个,考虑定义所有五个(析构、拷贝构造、拷贝赋值、移动构造、移动赋值)