如何禁止C++默认成员函数

发表于 2016-03-02   |   分类于 C++  |   阅读次数 17

前言

前几天在一次笔试过程中被问到C++如何设计禁止调用默认构造函数,当时简单的想法是直接将默认构造函数声明为private即可,这样的话对象的确不能直接调用。之后查阅了《Effective C++》之后得到了比较详尽的解释。

了解C++的默认行为

当我们创建空类时,C++默认给我们生成了四种成员函数:

  1. 构造函数
  2. 析构函数
  3. 拷贝构造函数(copy)
  4. 重载=的拷贝函数(copy assignment)

因此,当你写下如下的代码:

1
class Empty{};

那么编译器会自动生成:

class Empty{
public:
Empty(){...} //default构造函数
Empty(const Empty& rhs){...} //copy构造函数
~Empty(){...} //析构函数
Empty& operator=(const Empty& rhs){...} //copy assignment操作符
};

至于copy构造函数和copy assignment操作符是不是有效取决于类的成员变量,例如:如果类成员有const变量或者引用,那么是不能重新赋值的。

拒绝使用编译器自动生成函数

书中提到了一个实际的应用场景。在房子销售时,每一套房子都是独一无二的(地理位置,装修等等),那么显然我们不想让别人使用拷贝构造函数或者copy assignment操作符。但是如果我们不写,那么编译器会自动生成。如果我们写了就会可能让别人利用。那么该怎么办呢?

  • 首先我们最自然的想法就是把这两个函数声明为私有,这样别人调用的时候可能会报错。我们的直觉是正确的。确实这样做可以行得通。于是我们如此写到:
class HomeForSale{
public:
...
private:
HomeForSale(const HomeForSale& hfs){...}
HomeForSale& operator=(const HomeForSale& hfs){...}
};
  • 当然那么做并不是万事大吉了。因为member函数和友元函数仍然能调用私有成员函数。那么你可能又想到答案:我们无需定义成员函数,只需声明即可:
class HomeForSale{
public:
...
private:
HomeForSale(const HomeForSale&);
HomeForSale& operator=(const HomeForSale&);
};

那么member成员函数和友元函数调用时,在编译阶段没问题,在链接阶段会报错。那么还有没有更好的方案能够让代码在编译阶段就能检测出错误呢? 答案是肯定的。

  • 我们为此建立一个基类:
class Uncopyable{
protected:
Uncopyable(){} //允许derived对象的构造和解析
~Uncopyable(){}
private:
Uncopyable(const Uncopyable&); //但阻止copying
Uncopyable& operator=(const Uncopyable&);
};

那么,为了阻止HomeForSale被拷贝,我们只需继承Uncopyable:

class HomeForSale:private Uncopyable{
...
};
  • C++11提出更为简洁的解决方案:
class HomeForSale{
public:
HomeForSale(const HomeForSale&) = delete;
HomeForSale& operator=(const HomeForSale&) = delete;
};

总结

  • 为驳回编译器自动生成的成员函数,可将相应成员函数声明为private并且不予实现。或者使用像Uncopyable这样的基类。或者使用C++11的新特性。

  • 在boost也有这样的基类:noncopyable。

 
 

如何禁止C++默认成员函数的更多相关文章

  1. vc MFC 通过IDispatch调用默认成员函数

    CComPtr<IDispatch> spDisp(IDispatch *); if(!spDisp) return; DISPPARAMS dispParam={0}; //没有参数 V ...

  2. C++默认成员函数

    1.什么是面向对象? 概念:(Object Oriented Programming,缩写:OOP)是一种程序设计范型,同时也是一种程序开发的方法. 对象指的是类的实例,将对象作为程序的基本单元,将程 ...

  3. C++中的默认成员函数

    一般而言,对于一个用户自定义的类类型,以下四个函数在用户没有自定义的情形下,会由编译器自动生成: 1.default constructor 2.copy constructor Someclass: ...

  4. C++中的类继承(2)派生类的默认成员函数

    在继承关系里面, 在派生类中如果没有显示定义这六个成员 函数, 编译系统则会默认合成这六个默认的成员函数. 构造函数. 调用关系先看一段代码: class Base { public : Base() ...

  5. C++类的默认成员函数

    成员函数隐含this指针参数: 每成员函数一个隐式的指针形参(构造函数除外): 对象在调用成员函数时,编译器会将对象的地址传递给this指针: 1.构造函数(需用一个公有成员函数对私有的成员变量进行初 ...

  6. 堆(stack) 之 c 和 c++模板实现(空类默认成员函数 初谈引用 内联函数)

    //stack 的基本操作 #include <iostream> using namespace std; const int maxn = 3; typedef struct Stac ...

  7. String类的四个默认成员函数

    优化版的拷贝构造函数,先创建一个暂时实例tmp,接着把tmp._ptr和this->_ptr交换,因为tmp是一个局部变量.程序执行到该函数作用域外,就会自己主动调用析构函数.释放tmp._pt ...

  8. 【C++缺省函数】 空类默认产生的6个类成员函数

    1.缺省构造函数. 2.缺省拷贝构造函数. 3. 缺省析构函数. 4.缺省赋值运算符. 5.缺省取址运算符. 6. 缺省取址运算符 const. <span style="font-s ...

  9. C++继承具体解释之二——派生类成员函数具体解释(函数隐藏、构造函数与兼容覆盖规则)

    在这一篇文章開始之前.我先解决一个问题. 在上一篇C++继承详解之中的一个--初探继承中,我提到了在派生类中能够定义一个与基类成员函数同名的函数,这样派生类中的函数就会覆盖掉基类的成员函数. 在谭浩强 ...

随机推荐

  1. Maven进行自动构建

    一个很常见的错误就是路径问题,要把jdk放到java工程的路径里,之前一直默认是jre https://blog.csdn.net/lslk9898/article/details/73836745  ...

  2. OpenGL 学习总结

    最终呈现画出三角形的一个方式: public void draw(float[] mvpMatrix) { // Add program to OpenGL ES environment GLES20 ...

  3. cs224d 作业 problem set2 (二) TensorFlow 实现命名实体识别

    神经网络在命名实体识别中的应用 所有的这些包括之前的两篇都可以通过tensorflow 模型的托管部署到 google cloud 上面,发布成restful接口,从而与任何的ERP,CRM系统集成. ...

  4. s-cms学校建站重装漏洞

    文件位置 ./install/index.php 影响版本 PHP V5.0 过程 通过获取GET请求判断是安装还是结束安装 安装步骤1 安装步骤2 安装步骤3 安装步骤4 解释 安装步骤1-3都没有 ...

  5. 点读系列《流畅的python》

    第1章 python数据模型 python的写法是由背后的魔法方法实现的,比如obj[key],解释器实际调用的是obj.__getitem__(key) 作者把魔法方法叫做双下方法,因为有两个下划线 ...

  6. 深入了解line-height(各种单位总结1.5/150%/1.5em)

    默认状态,浏览器使用1.0-1.2 line-height, 这是一个初始值.你可以定义line-height属性来覆盖初始值:p{line-height:140%} 你可以有5种方式来定义line- ...

  7. Zookeeper安装配置及简单使用

    我使用的CentOS 7阿里云服务器,ZK依赖JDK,需要先安装jdk并配置jdk环境变量. 1.安装wget: yum –y install wget 2.下载Zookeeper(http://mi ...

  8. css图片文字

    1.浏览器是把 html 和 css 一起下载并执行的,计算机里把两件事情同时做  异步加载.计算机中的同步异步和我们生活中的正好是相反的. 补充: 同步,是所有的操作都做完,才返回给用户结果.即写完 ...

  9. 使用python+ffmpeg批量转换格式

    需求:  给定一个文件夹路径,遍历该文件夹内的所有文件以及子文件夹内的文件,当所有后缀名为wav格式的文件转换为ogg格式的文件. import os # 获取目录下的所有文件列表 import fn ...

  10. JNI中修改(基本类型)参数并返回到Java层使用

    最近在JNI相关项目中遇到一个问题:在Java层传入多个int类型的参数,在jni层修改参数值或地址之后重新返回到Java层.这应该算是基本知识了,尤其是基本类型的参数往往看似简单,所以在之前学习jn ...