转自:http://blog.jobbole.com/103669/
default函数
default函数作用于类的特殊成员函数,为其自动生成默认的函数定义体,提高代码的执行效率。
类的特殊成员函数:
- 默认构造函数
- 析构函数
- 复制构造函数
- 拷贝赋值运算符
- 取址运算符
- const取址运算符
前四个特殊函数负责实例化对象、销毁对象以及复制对象。如果类中没有定义构造函数,则会生成一个默认构造函数。
#include<iostream>
using namespace std;
class A {
public:
int get() {
return a;
}
private:
int a;
};
int main(int argc, char* argv[]) {
A A1; //可以实例化对象,类有默认构造函数
cout << A1.get() << endl;
getchar();
return 0;
}
- 但当类中含有构造函数时,类不会为其生成默认构造函数:
#include<iostream>
using namespace std;
class A {
public:
A(int a) {
this->a = a;
}
int get() {
return a;
}
private:
int a;
};
int main(int argc, char* argv[]) {
//A A1; //错误:类A不存在默认构造函数
A A2(10); //正确:调用带参的构造函数
cout << A2.get() << endl; //10
getchar();
return 0;
}
- 倘若我们想使用默认构造函数,则必须显式地定义:
class A {
public:
A(){} //显式地定义
A(int a) {
this->a = a;
}
int get() {
return a;
}
private:
int a;
};
显式地定义默认构造函数存在问题:手动编写的特殊成员函数的代码执行效率比编译器自动生成的特殊函数低!
此时default函数就正式登场了。C++11标准引入了一个新特性:default函数。程序员只需在类的特殊成员函数声明后加上“=default;”,就可将该函数声明为 defaulted 函数,编译器将为显式声明的 defaulted 函数自动生成函数体。
class A {
public:
A() = default; //自动生成函数体
A(int a) {
this->a = a;
}
int get() {
return a;
}
private:
int a;
};
注意:
- default函数仅适用于类的特殊成员函数,且该特殊成员函数没有默认参数。
- default函数既可以在类内声明类外定义,也可以在类内直接定义。
class A {
public:
A() = default; //自动生成函数体,类内定义
//A(double d) = default; //错误:类型对于默认构造函数无效
A(int a) {
this->a = a;
}
A(const A& it);
//int get() = default; //错误:=default只能出现在默认构造函数、析构函数、复制构造函数、赋值运算符中
private:
int a;
};
A::A(const A& it) = default; //类内声明,类外定义
deleted函数
编译器会对指定的函数禁用,从而避免了某些非法的函数调用或者类型转换,从而提高了代码的安全性。
对于 C++ 的类,如果程序员没有为其定义特殊成员函数,那么在需要用到某个特殊成员函数的时候,编译器会隐式的自动生成一个默认的特殊成员函数,上面我们提到默认构造函数,还有复制构造函数,拷贝赋值操作符。(当初始化对象时调用的是复制构造函数,已经初始化过的对象调用的是赋值运算符)
#include<iostream>
using namespace std;
class A {
public:
A() = default; //自动生成函数体,类内定义
A(int a) {
this->a = a;
}
private:
int a;
};
int main(int argc, char* argv[]) {
A A1(10);
A A2 = A1; //正确,调用编译器隐式生成的默认复制构造函数
A A3(20);
A2 = A3; //正确,调用编译器隐式生成的赋值运算符
getchar();
return 0;
}
编译器能隐式地生成复制构造函数和赋值运算符当然有其优点:为程序员省掉了一些代码量,但在某些情况下,我们不允许发生类对象之间的复制和赋值,可是又无法阻止编译器隐式自动生成默认的拷贝构造函数以及拷贝赋值操作符,那这就成为一个问题了。
deleted函数正式登场了。C++11 标准引入了一个新特性:deleted 函数。程序员只需在函数声明后加上“=delete;”,就可将该函数禁用。
#include<iostream>
using namespace std;
class A {
public:
A() = default; //自动生成函数体,类内定义
A(int a) {
this->a = a;
}
A(const A& it) = delete;
A& operator=(const A& it) = delete;
private:
int a;
};
int main(int argc, char* argv[]) {
A A1(10);
//A A2 = A1; //错误:复制构造函数是已删除的函数
A A3(20);
//A2 = A3; //错误:赋值运算符函数是已删除的函数
getchar();
return 0;
}
注意
- 必须在函数第一次声明的时候将其声明为 deleted 函数,否则编译器会报错。
- deleted 函数特性可以作用于类的特殊成员函数、类的非特殊成员函数、普通函数。。
#include<iostream>
using namespace std;
class A {
public:
A() = default; //自动生成函数体,类内定义
A(int a) {
this->a = a;
}
A(const A& it);
A& operator=(const A& it) = delete; //正确:“=delete”出现在函数的第一个声明中
int get() = delete; //正确:“=delete”特性可以作用于类的非特殊成员函数
private:
int a;
};
//A::A(const A& it) = delete; //错误:“=delete”只能出现在函数的第一个声明中
int fun1() = delete; //正确:“=delete”特性可以作用于普通函数
int main(int argc, char* argv[]) {
A A1(10);
//A A2 = A1; //错误:复制构造函数是已删除的函数
A A3(20);
//A2 = A3; //错误:赋值运算符函数是已删除的函数
//A3.get(); //错误:get()函数是已删除的函数
getchar();
return 0;
}