C++常谈的大三元,五元, 以及默认构造器析构器, 私有函数问题.
defaulted和deleted函数, 期间谈到了 big-three, boost::noncopyable, 友元等问题
两种类型的函数, 都是只用声明, 不用实现的函数, 一般是指
- 构造函数(包括拷贝类的, 移动类的)
- 析构函数
- 赋值函数
这些函数一般都是inline的.
但是很少用于一般函数, 只用于Big-three或者 Big-five.
关于编译器会生成和自动调用什么, 请参考<Effective C++>
简单说, 类成员有pointer member时, 基本上就要写出来 Big-three了;
比如说字符串这个类, 肯定设计按位拷贝和深拷贝问题, 所以必写; 换句话说, 涉及深拷贝浅拷贝的类, 要写大三元
.
下面分别说一下deleted和defaulted函数.
defaulted 函数, 默认构造和析构函数, =default;
声明即可, 不必提供实现.
指示编译器生成该函数的默认实现有两个好处:
- 即便你自己提供了, 编译器还是保留一个默认提供的
- 有更好的性能
例如:
1 | struct A |
deleted 函数, 即=delete
声明的函数; 目的是不让你使用了, 比如单例模式, 比如防止对象拷贝:
1 | struct NoCopy |
不同于纯虚函数
的=0;
语法, 它的意思表示这个函数让子类去实现; 而=delete;
主要是防止从外部调用.
去我们不让别人调用, 可以使用private修饰, 现在delete修饰的, 直接所有人都禁用了.
所以, 如果你的类存在友元, 那么最好还是保留成private的, 留个后门.
实际上,
boost::noncopyable
就是这么做的
Boost::noncopyable
把拷贝构造和拷贝赋值私有化了, 以此来保证子类是不可拷贝的.
因为子类拷贝的函数, 不管是赋值还是构造, 总要处理父类部分吧, 而父类boost::noncopyable明确说了, 我是可拷贝的; 所以不管子类如何折腾, 拷贝还是放弃吧.
但是类的友元还是可以使用的, 类似下面的实现.
1 | namespace boost |
可以看到, 并没有用到delete
关键字.
在effective c++中, 作者还调侃过,
noncopyable
不是该叫做uncopyable
嘛?纯粹的, 很有趣啊