C++武器库之default成员函数

我是FFZero,一个10年开发经验的cpper。

C++武器库系列尝试带领大家认识开发中常用的基础知识和工具类,补充项目工具库中的底层原理,

在C++11中引入的**=default语法是一个重要的新特性,它允许程序员显式地请求编译器为类生成默认版本的特殊成员函数**。这些特殊成员函数包括默认构造函数、拷贝构造函数、移动构造函数、拷贝赋值运算符、移动赋值运算符以及析构函数。使用default可以让编译器根据语言规则自动生成这些函数的高效实现,而不是由程序员手动编写。

为什么需要default成员函数?

普通类型(trivial type)

请思考,下面class A的两个构造函数有什么区别?

class A
    {
    public:
        // ...
        A() {}          // 定义一个空的默认构造函数,non-trivial type
        A() = default;  // 主动让编译器生成默认构造函数, trivial type
        // ...
    };

C++ 中有概念叫trivial type,可以简单翻译成“普通(平凡)类型”。 详细了解可以参考链接Trivial, standard-layout, POD, and literal types

简单总结:
当一个类型(class / struct )同时满足以下几个条件时,它就是 trivial type:

  1. 没有虚函数或虚基类。
  2. 由编译器生成默认的特殊成员函数,包括默认构造函数、拷贝构造函数、移动构造函数、赋值运算符、移动赋值运算符和析构函数。
  3. 基类和数据成员同样需要满足条件 1 和 2

所以,上面的例子中,如果使用了 A() {} 则 class A是non-trivial type;如果使用的是A()=default; 则class A是trivial type。编译器可以对平凡构造函数进行各种优化,可能比用户空实现的构造函数性能更好。

怎么判断一个类是不是trivial type?

可以通过static_assert静态断言配合std::is_trivial::value判断某个类是否trivial.

class A {
}
static_assert(!std::is_trivial<A>::value);  //A不是trivial

default成员函数用法

  1. 定义了带参数的构造函数时还希望使用默认构造函数

在某些情况下,当你定义了类的一个或多个构造函数时,编译器将不会自动生成默认构造函数。这可能是因为你提供了其他形式的构造函数,比如带参数的构造函数。在这种情况下,如果你还需要一个默认构造函数来创建对象,你就必须自己提供一个实现。但是,有时候这个默认构造函数的行为只需要是简单的默认初始化,这时手动编写可能会显得冗余且效率不高。通过使用=default;,你可以让编译器为你生成这样一个高效的默认构造函数,而不需要你自己去写。

class MyClass {
 public:
  MyClass() = default;  // 提供缺省的构造函数
  MyClass(int v):x(y) {}
  MyClass(const MyClass& other) = default;  // 提供缺省的拷贝构造函数
  MyClass& operator=(const MyClass& other) = default;  // 提供缺省的拷贝赋值运算符
  // 其他成员函数
 private:
  int x;
};

结合我们上一节介绍的trivial type,请思考下面代码中:
哪些类是trival type,哪些类不是trival type?

#include <type_traits>

class A {
public:
    A(int i) : n(i) {}      
    A() {}             //默认构造函数提供了自己的实现
private:
    int n;
};

class B {
public:
    B(int i) : n(i) {}
    B() = default;     //编译器生成默认的构造函数
private:
    int n;
};

class C {
public:
    C(int i) : n(i) {} //提供了一个带参数的构造函数,而没有默认构造函数,编译器不会为C生成默认构造函数
private: 
    int n;
};

class D {
private: 
    int n;
};

static_assert(!std::is_trivial<A>::value);  //A不是trivial
static_assert(std::is_trivial<B>::value);   //B是trivial
static_assert(!std::is_trivial<C>::value);  //C不是trivial
static_assert(std::is_trivial<D>::value);  //D是trivial,所有构造函数都由编译器默认生成

你做对了吗?

  1. default成员函数仅适用于没有默认参数的特殊成员函数。如果你试图在一个有默认参数的构造函数上使用=default,将会导致编译错误。

  2. default成员函数不能用于非特殊成员函数。这个很好理解,普通成员函数编译器没法默认生成。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值