禁用编译器自动生成的函数(Effective C++之06)
如果想让你的类定义出来的对象是独一无二的,即对象无法被复制,或者使用赋值操作符赋给另外一个对象,那么最好的方法就是禁用拷贝构造函数和赋值操作符。下面介绍几种禁用的方法。(方法来自Effective C++,如果想禁用类的其他函数,方法类似)
1. 定义为private且不实现它
我们知道,拷贝构造函数和赋值操作符重载函数,即使不定义,编译器也会生成一个默认的函数。但是如果定义了,class还是会支持这两个函数。那么应该怎么去禁用它们呢?
在C++中,如果不想让对象调用某个方法,那么可以将这个方法声明为private,因此,我们可以将拷贝构造函数和赋值操作符重载函数声明为private,就可以阻止别人调用它了。但是,private函数还是可以在类的成员函数和friend函数中调用。这里还有一个技巧,就是将函数定义为private而且不实现它。
class SpecialClass {
...
private:
SpecialClass(const SpecialClass&);
SpecialClass& operator=(const SpecialClass&);
};
将SpecialClass这样定义,并且不实现这两个函数,那么如果有人试图拷贝这个类的对象,编译器就会报错:
SpecialClass sc1;
SpecialClass sc2(sc1); //error, 编译出错
SpecialClass sc3;
sc3 = sc1; //error, 编译出错
而且即使在成员函数或者friend函数中调用了它,链接时也会出错。
2. 继承Uncopyable类
第一种方法可以解决禁用拷贝构造函数的问题,但是还有一点不完美的是,如果用户不小心在成员函数或者friend函数中调用了它,那么这个错误只有到链接阶段才能被发现。所以就有了继承一个Uncopyable类的方法:
class Uncopyable {
protected:
Uncopyable() {}
~Uncopyable() {}
private:
Uncopyable(const Uncopyable&);
Uncopyable& operator=(const Uncopyable&);
};
此时,只需要继承Uncopyable类就可以防止其对象被拷贝了。其原理是:SpecialClass继承了Uncopyable函数,它的对象如果调用了拷贝构造函数,或者使用了赋值操作符,那么编译时,就会去调用基类的对应函数,但是基类里的这两个函数是private的,所以编译会失败。
另外,boost也提供了一个Uncopyable函数,那个class名字为noncopyable,因此我们也可以这样做:
#include <boost/utility.hpp>
class SpecialClass : boost::noncopyable {
...
};
3. C++0x中的新方法
在C++0x中,新添加了两个关键字:default和delete,可以用于控制某个类使用默认函数(default)或者禁用某个函数(delete)。其中,使用default关键字可以将某个函数定义为默认函数。如:
class SpecialClass {
...
public:
SpecialClass(const SpecialClass&) = default;
SpecialClass& operator=(const SpecialClass&) = default;
};
可能这样写有点多余,但是它可以直观表示“我使用的默认的函数”。而且,如果有人想显式定义默认函数,但是自己写的代码又可能有错误,就可以使用这个关键字,方便且不出错。
delete关键字可以禁用掉类的方法,正如我们上面前两节所做的事情,就可以用这一个关键字完成:
class SpecialClass {
...
public:
SpecialClass(const SpecialClass&) = delete; //禁用拷贝构造函数
SpecialClass& operator=(const SpecialClass&) = delete;
};
default关键字可以用于一切含有默认方法的函数。delete关键字可以用于类的所有方法,例如可以禁用掉函数的某些类型的参数:
class SpecialClass {
...
public:
void fn(long);
void fn(int) = delete;
};
SpecialClass sc;
long l;
sc.fn(l); //ok, 调用void fn(long);
int i;
sc.fn(i); //error, 调用void fn(int);
上面的代码会将void fn(int)类型的函数禁用掉,而如果不禁用的话,sc.fn(i)会进行隐式转换调用void fn(long)函数。
参考:
文章摘自 xd_xiaoxin 的博文。
禁用编译器自动生成的函数(Effective C++之06)的更多相关文章
- Effective C++ 之 Item 6 : 若不想使用编译器自动生成的函数,就该明确拒绝
Effective C++ chapter 2. 构造 / 析构 / 赋值运算 (Constructors, Destructors, and Assignment Operators) Item 6 ...
- 【Effective c++】条款6:若不想使用编译器自动生成的函数就应该明确拒绝
地产中介卖的是房子,其使用的中介软件系统应该有个类用来描述卖掉的房子 class HomeFoeSale { ......} 但是任何房子都是独一无二的,不应该存在两个房子拥有同样的属性,因此以下操作 ...
- Effective C++_笔记_条款06_若不想使用编译器自动生成的函数,就该明确拒绝
(整理自Effctive C++,转载请注明.整理者:华科小涛@http://www.cnblogs.com/hust-ghtao/) 通常如果你不希望class支持某一特定机能,只要不声明对应函数就 ...
- 读书笔记 effective c++ Item 6 如果你不想使用编译器自动生成的函数,你需要明确拒绝
问题描述-阻止对象的拷贝 现实生活中的房产中介卖房子,一个服务于这个中介的软件系统很自然的会有一个表示要被销售的房屋的类: class HomeForSale { ... }; 每个房产中介会立刻指出 ...
- Effective C++ -----条款06:若不想使用编译器自动生成的函数,就该明确拒绝
为驳回编译器自动提供的功能,可将相应的成员函数声明为private并且不予实现. 使用像Uncopyable这样的base class也是一种做法(即先声明一个基类,然后私有继承它).这其实有点像使用 ...
- Effective C++学习笔记 条款06:如不想使用编译器自动生成的函数,就该明确拒绝
一.为驳回编译器自动提供的机能,可将相应成员函数声明为private并且不予实现.(如果你仅仅是自己不实现的话,编译器会帮你实现) 如: class A { public: A(const strin ...
- Effective C++ 条款06:若不想使用编译器自动生成的函数,就该明确拒绝
规则一 将成员函数声明为private而且故意不实现他们 class HomeForSale { public: ... private: ... HomeForSale(const HomeForS ...
- Effective C++ 条款六 若不想使用编译器自动生成的函数,就该明确拒绝
class HomeForSale //防止别人拷贝方法一:将相应的成员函数声明为private并且不予实现 { public: private: HomeForSale(const HomeForS ...
- C++如何拒绝编译器自动生成的函数
每一个class,编译器都会自动生成四个特殊成员函数: destructor(析构函数) default constructor(默认构造函数) copy constructor(copy构造函数) ...
随机推荐
- 【GoLang】GoLang 单元测试、性能测试使用方法
单元测试代码: ackage test import ( // "fmt" "testing" ) func Test_FlowControl(t *testi ...
- git日志输出格式及两个版本之间差异列表
查看commit id git log --pretty=format:"%h" git log --pretty=format:"%H" 获取两个版本间差异的 ...
- iOS CLLocationManager 定位
今天写个定位,本来很简单,但是在填写plist时,通过系统提示,只能看到NSLocationUsageDescription项目,根本不提示 (1)NSLocationAlwaysUsageDescr ...
- java mail api 使用
所需要的jar包: http://pan.baidu.com/s/1qWGZRJm 如果遇到这个错误:在windows防火墙允许 javaw.exe访问网络.或者关闭防火墙 FATAL ERROR i ...
- win8开发wpf程序遇到的无语问题
在设置wpf程序全屏后,点击某个listbox列表,发现程序下面出现了任务栏. 查找解决答案未果.仔细一想可能是win8系统的问题. 最后试着把listbox的滚动条去掉了,问题解决. 原因:当程序中 ...
- linux 共享内存实现
说起共享内存,一般来说会让人想起下面一些方法:1.多线程.线程之间的内存都是共享的.更确切的说,属于同一进程的线程使用的是同一个地址空间,而不是在不同地址空间之间进行内存共享:2.父子进程间的内存共享 ...
- codeforces 507B. Painting Pebbles 解题报告
题目链接:http://codeforces.com/problemset/problem/509/B 题目意思:有 n 个piles,第 i 个 piles有 ai 个pebbles,用 k 种颜色 ...
- Gson解析复杂的json数据
最近在给公司做一个直播APK的项目,主要就是通过解析网络服务器上的json数据,然后将频道地址下载下来再调用Android的播放器进行播放,原先本来打算使用普通的json解析方法即JsonObject ...
- phpexcel生成excel并下载
Loader::import('PHPExcel.Classes.PHPExcel'); // tp5中只需将phpexcel文件放入extend文件夹中,即可采用该方法引入,需要先 use thin ...
- Hibernate 所有缓存机制详解
hibernate提供的一级缓存 hibernate是一个线程对应一个session,一个线程可以看成一个用户.也就是说session级缓存(一级缓存)只能给一个线程用,别的线程用不了,一级缓存就是和 ...