Defaulted 函数
背景
C++ 的类有四类特殊成员函数,它们分别是:默认构造函数、析构函数、拷贝构造函数以及拷贝赋值运算符。这些类的特殊成员函数负责创建、初始化、销毁,或者拷贝类的对象。如果程序员没有显式地为一个类定义某个特殊成员函数,而又需要用到该特殊成员函数时,则编译器会隐式的为这个类生成一个默认的特殊成员函数。
例1:
class X
{
private:
int a;
};
X x;
分析:上述代码中并没有定义类 X 的默认构造函数,但是在创建类 X 的对象 x 的时候,又需要用到类 X 的默认构造函数,编译器会隐式的为类 X 生成一个默认构造函数。该自动生成的默认构造函数没有参数,包含一个空的函数体,即 X::X(){ }。
例2:
class X
{
public:
X(int i){ a = i; }
private:
int a;
};
X x; // 错误 , 默认构造函数 X::X() 不存在
分析:类 X 已经有了自定义的构造函数,所以编译器将不再会为它隐式的生成默认构造函数。如果需要用到默认构造函数来创建类的对象时,必须显式的定义默认构造函数。
Defaulted 函数的提出
手动编写的默认构造函数的代码执行效率比编译器自动生成的默认构造函数低。类的其它几类特殊成员函数也和默认构造函数一样,当存在自定义的特殊成员函数时,编译器将不会隐式的自动生成默认特殊成员函数,而需要手动编写,加大了工作量。类似的,手动编写的特殊成员函数的代码执行效率比编译器自动生成的特殊成员函数低。C++11 标准引入了一个新特性:defaulted 函数。只需在函数声明后加上“=default;”,就可将该函数声明为 defaulted 函数,编译器将为显式声明的 defaulted 函数自动生成函数体。
例3:
class X
{
public:
X()= default;
X(int i){ a = i; }
private:
int a;
};
X x;
分析:编译器会自动生成默认构造函数 X::X(){},该函数可以比用户自己定义的默认构造函数获得更高的代码效率。
Defaulted 函数的用法及示例
Defaulted 函数特性仅适用于类的特殊成员函数,且该特殊成员函数没有默认参数。既可以在类体里(inline)定义,也可以在类体外(out-of-line)定义。
例4:
class X{
public:
int f() = default; // 错误,函数f()非类 X 的特殊成员函数
X(int) = default;// 错误,构造函数X(int)非X的特殊成员函数
X() = default; //默认构造函数(内联函数)
X(const X&);
X& operator = (const X&);
~X() = default; //析构函数(内联函数)
};
X::X(const X&) = default; // 拷贝构造函数(外联函数)
X& X::operator = (const X&) = default; //拷贝赋值操作符(外联函数)
例5:
class X
{
private:
int x;
};
class Y: public X
{
private:
int y;
};
int main()
{
X* x = new Y;
delete x;
}
分析:
代码中没有为基类 X 和派生类 Y 定义析构函数,当在主函数内 delete 基类指针 x 的时候,需要调用基类的析构函数。于是,编译器会隐式自动的为类 X 生成一个析构函数,从而可以成功的销毁 x 指向的派生类对象中的基类子对象(即 int 型成员变量 x)。但是,这段代码存在内存泄露的问题,当利用 delete 语句删除指向派生类对象的指针 x 时,系统调用的是基类的析构函数,而非派生类 Y 类的析构函数,因此,编译器无法析构派生类的 int 型成员变量 y。因此,一般情况下需要将基类的析构函数定义为虚函数,当利用 delete 语句删除指向派生类对象的基类指针时,系统会调用相应的派生类的析构函数(实现多态性),从而避免内存泄露。但是编译器隐式自动生成的析构函数都是非虚函数,这就需要由手动的为基类 X 定义虚析构函数。
为了解决上述问题,可以将基类的虚析构函数声明为 defaulted 函数,就可以显式的指定编译器为该函数自动生成函数体。
例6:
class X
{
virtual ~X()= defaulted;//编译器自动生成defaulted函数定义体
private:
int x;
};
class Y: public X
{
private:
int y;
};
int main()
{
X* x = new Y;
delete x;
}
分析:编译器会自动生成虚析构函数 virtual X::X(){},该函数比用户自己定义的虚析构函数具有更高的代码执行效率。
总结
对于 defaulted 函数,编译器会为其自动生成默认的函数定义体,从而获得更高的代码执行效率,也可免除手动定义该函数的工作量。