技术: C++11 默认函数问题探究

C++常谈的大三元,五元, 以及默认构造器析构器, 私有函数问题.

defaulted和deleted函数, 期间谈到了 big-three, boost::noncopyable, 友元等问题


两种类型的函数, 都是只用声明, 不用实现的函数, 一般是指

  • 构造函数(包括拷贝类的, 移动类的)
  • 析构函数
  • 赋值函数

这些函数一般都是inline的.

但是很少用于一般函数, 只用于Big-three或者 Big-five.

关于编译器会生成和自动调用什么, 请参考<Effective C++>

简单说, 类成员有pointer member时, 基本上就要写出来 Big-three了;

比如说字符串这个类, 肯定设计按位拷贝和深拷贝问题, 所以必写; 换句话说, 涉及深拷贝浅拷贝的类, 要写大三元.


下面分别说一下deleted和defaulted函数.

defaulted 函数, 默认构造和析构函数, =default;声明即可, 不必提供实现.
指示编译器生成该函数的默认实现有两个好处:

  • 即便你自己提供了, 编译器还是保留一个默认提供的
  • 有更好的性能

例如:

1
2
3
4
5
6
struct A
{
A()=default;
A(int i){}
virtual ~A()=default;
};

deleted 函数, 即=delete声明的函数; 目的是不让你使用了, 比如单例模式, 比如防止对象拷贝:

1
2
3
4
5
6
7
struct NoCopy
{
NoCopy& operator =( const NoCopy& ) = delete;
NoCopy ( const NoCopy & ) = delete;
};
NoCopy a;
NoCopy b(a); //编译错误,拷贝构造函数是 deleted 函数

不同于纯虚函数=0;语法, 它的意思表示这个函数让子类去实现; 而=delete;主要是防止从外部调用.

去我们不让别人调用, 可以使用private修饰, 现在delete修饰的, 直接所有人都禁用了.

所以, 如果你的类存在友元, 那么最好还是保留成private的, 留个后门.

实际上, boost::noncopyable就是这么做的

Boost::noncopyable 把拷贝构造和拷贝赋值私有化了, 以此来保证子类是不可拷贝的.
因为子类拷贝的函数, 不管是赋值还是构造, 总要处理父类部分吧, 而父类boost::noncopyable明确说了, 我是可拷贝的; 所以不管子类如何折腾, 拷贝还是放弃吧.

但是类的友元还是可以使用的, 类似下面的实现.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
namespace boost
{
namespace noncopyable_
{
class noncopyable
{
protected:
noncopyable(){}
~noncopyable(){}

private:
noncopyable(const noncopyable&);
const noncopyable& operator=(const noncopyable& );
}
}
};

可以看到, 并没有用到delete关键字.

在effective c++中, 作者还调侃过, noncopyable不是该叫做uncopyable嘛?

纯粹的, 很有趣啊

文章目录
|