C++11 理解 (十九) 之 使用或禁用对象的默认函数

来源:互联网 发布:linux c语言遍历目录 编辑:程序博客网 时间:2024/05/22 20:20

在传统C++中,若用户没有提供, 则编译器会自动为对象生成默认构造函数(default constructor)、 复制构造函数(copy constructor),赋值运算符(copy assignment operator operator=) 以及析构式(destructor)。另外,C++也为所有的类定义了数个全局运算符(如operator deleteoperator new)。当用户有需要时,也可以提供自定义的版本改写上述的函数。

问题在于原先的c++无法精确地控制这些默认函数的生成。 比方说,要让类型不能被拷贝,必须将复制构造函数与赋值运算符声明为private,并不去定义它们。 尝试使用这些未定义的函数会导致编译期或链接期的错误。 但这种手法并不是一个理想的解决方案。

此外,编译器产生的默认构造函数与用户定义的构造函数无法同时存在。 若用户定义了任何构造函数,编译器便不会生成默认构造函数; 但有时同时带有上述两者提供的构造函数也是很有用的。 目前并没有显式指定编译器产生默认构造函数的方法。

C++11 允许显式地表明采用或拒用编译器提供的自带函数。例如要求类型带有默认构造函数,可以用以下的语法:

struct SomeType{  SomeType() = default; // 預設建構式的顯式聲明  SomeType(OtherType value);};

另一方面,也可以禁止编译器自动产生某些函数。如下面的例子,类型不可复制:

struct NonCopyable{  NonCopyable & operator=(const NonCopyable&) = delete;  NonCopyable(const NonCopyable&) = delete;  NonCopyable() = default;};

禁止类型以operator new配置内存:

struct NonNewable{  void *operator new(std::size_t) = delete;};

此种对象只能生成于 stack 中或是当作其他类型的成员,它无法直接配置于 heap 之中,除非使用了与平台相关,不可移植的手法。 (使用 placement new 运算符虽然可以在用户自配置的内存上调用对象构造函数,但在此例中其他形式的 new 运算符一并被上述的定义 屏蔽("name hiding"),所以也不可行。)

= delete的声明(同时也是定义)也能适用于非自带函数, 禁止成员函数以特定的形参调用:

struct NoDouble{  void f(int i);  void f(double) = delete;};

若尝试以 double 的形参调用 f(),将会引发编译期错误, 编译器不会自动将 double 形参转型为 int 再调用f()。 若要彻底的禁止以非int的形参调用f(),可以将= delete与模板相结合:

struct OnlyInt{  void f(int i);  template<class T> void f(T) = delete;};
原创粉丝点击