我是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
所以,上面的例子中,如果使用了 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成员函数用法
- 定义了带参数的构造函数时还希望使用默认构造函数
在某些情况下,当你定义了类的一个或多个构造函数时,编译器将不会自动生成默认构造函数。这可能是因为你提供了其他形式的构造函数,比如带参数的构造函数。在这种情况下,如果你还需要一个默认构造函数来创建对象,你就必须自己提供一个实现。但是,有时候这个默认构造函数的行为只需要是简单的默认初始化,这时手动编写可能会显得冗余且效率不高。通过使用=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,所有构造函数都由编译器默认生成
你做对了吗?
-
default成员函数仅适用于没有默认参数的特殊成员函数。如果你试图在一个有默认参数的构造函数上使用=default,将会导致编译错误。
-
default成员函数不能用于非特殊成员函数。这个很好理解,普通成员函数编译器没法默认生成。
2011

被折叠的 条评论
为什么被折叠?



