如果想让你的类定义出来的对象是独一无二的,即对象无法被复制,或者使用赋值操作符赋给另外一个对象,那么最好的方法就是禁用拷贝构造函数和赋值操作符。下面介绍几种禁用的方法。(方法来自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)函数。

 

参考:

C++11 FAQ

 

 

 

文章摘自 xd_xiaoxin博文。

禁用编译器自动生成的函数(Effective C++之06)的更多相关文章

  1. Effective C++ 之 Item 6 : 若不想使用编译器自动生成的函数,就该明确拒绝

    Effective C++ chapter 2. 构造 / 析构 / 赋值运算 (Constructors, Destructors, and Assignment Operators) Item 6 ...

  2. 【Effective c++】条款6:若不想使用编译器自动生成的函数就应该明确拒绝

    地产中介卖的是房子,其使用的中介软件系统应该有个类用来描述卖掉的房子 class HomeFoeSale { ......} 但是任何房子都是独一无二的,不应该存在两个房子拥有同样的属性,因此以下操作 ...

  3. Effective C++_笔记_条款06_若不想使用编译器自动生成的函数,就该明确拒绝

    (整理自Effctive C++,转载请注明.整理者:华科小涛@http://www.cnblogs.com/hust-ghtao/) 通常如果你不希望class支持某一特定机能,只要不声明对应函数就 ...

  4. 读书笔记 effective c++ Item 6 如果你不想使用编译器自动生成的函数,你需要明确拒绝

    问题描述-阻止对象的拷贝 现实生活中的房产中介卖房子,一个服务于这个中介的软件系统很自然的会有一个表示要被销售的房屋的类: class HomeForSale { ... }; 每个房产中介会立刻指出 ...

  5. Effective C++ -----条款06:若不想使用编译器自动生成的函数,就该明确拒绝

    为驳回编译器自动提供的功能,可将相应的成员函数声明为private并且不予实现. 使用像Uncopyable这样的base class也是一种做法(即先声明一个基类,然后私有继承它).这其实有点像使用 ...

  6. Effective C++学习笔记 条款06:如不想使用编译器自动生成的函数,就该明确拒绝

    一.为驳回编译器自动提供的机能,可将相应成员函数声明为private并且不予实现.(如果你仅仅是自己不实现的话,编译器会帮你实现) 如: class A { public: A(const strin ...

  7. Effective C++ 条款06:若不想使用编译器自动生成的函数,就该明确拒绝

    规则一 将成员函数声明为private而且故意不实现他们 class HomeForSale { public: ... private: ... HomeForSale(const HomeForS ...

  8. Effective C++ 条款六 若不想使用编译器自动生成的函数,就该明确拒绝

    class HomeForSale //防止别人拷贝方法一:将相应的成员函数声明为private并且不予实现 { public: private: HomeForSale(const HomeForS ...

  9. C++如何拒绝编译器自动生成的函数

    每一个class,编译器都会自动生成四个特殊成员函数: destructor(析构函数) default constructor(默认构造函数) copy constructor(copy构造函数) ...

随机推荐

  1. 【GoLang】GoLang struct 使用

    代码示例: package main import "fmt" type Human struct { name string age int weight int } type ...

  2. DOS与批处理

    cmd命令不区分大小写 d: cd .. cd 文件夹 dir dir 文件或文件夹 可执行文件(.exe, .bat., .com),只需进入文件当前目录并输入文件名(不需要后缀)即可执行, 如果将 ...

  3. METEOR 及ANGULARJS

    最近学习:METEOR 及ANGULARJS,收藏相关资源: 1.METEOR 中文书:http://zh.discovermeteor.com/ 2.METEOR 及ANGULARJS 联合开发:h ...

  4. hdu2457

    AC自动机+DP #include <cstdio> #include <queue> #include <cstring> using namespace std ...

  5. Unity关于用LoadLevelAdditiveAsync导致新场景的Navmesh数据不正确Loading条的实践

    为了解决用Application.LoadLevelAdditiveAsync 导致新场景的Navmesh数据不正确(我们用的是4.63),我们现在loading条做法是先切到Loading的场景,然 ...

  6. delphi XE5下安卓开发技巧

    delphi XE5下安卓开发技巧 一.手机快捷方式显示中文名称 project->options->Version Info-label(改成需要显示的中文名即可),但是需要安装到安卓手 ...

  7. Java中的Comparable接口和Comparator接口

    Comparator位于包java.util下,比较器,是在集合外部定义排序.Comparable位于包java.lang下,代表当前对象可比较的,是在集合内部实现排序. Comparable代表一个 ...

  8. Django~Models2

    Generally, each model maps to a single database table. Each attribute of the model represents a data ...

  9. jsp中<!DOCTYPE>标签

    今天写代码时遇到一个问题,定义了如下一个样式: .c_c1:hover td { background-color: #edf5ce;} <tr class="c_c1"&g ...

  10. C#实现把指定文件夹下的所有文件复制到指定路径下以及修改指定文件的后缀名

    1.实现把指定文件夹下的所有文件复制到指定路径下 public static void copyFiles(string path) { DirectoryInfo dir = new Directo ...