Effective c++ 学习笔记(item6)

2021-09-08  本文已影响0人  懒生活

Effective c++ 学习笔记(item6)

Item6: Explicitly disallow the use of compiler-generated functions you do not want
题外话:从Item1到Item6,item1是总括介绍性的章节,虽然泛泛而谈,但要都理解也是不容易的。item2到item5这开头的几个章节说实话作者描述的知识点相当多。反倒是item6这一章是真简单。当然如果要把文中提到的多重继承问题也引申的搞透,那样子算的话也不简单。

什么情况下我们不想要赋值函数,拷贝构造函数

Scott举了个很实在的例子,比如有二手房产中介要卖房子,那么平台会有用一个类对象来保存房子的信息。每个房子都是独一无二的,程序平台就希望能够避免这种对象之间的赋值拷贝。伪代码如下

HomeForSale h1;
HomeForSale h2;
HomeForSale h3(h1); //这是没有意义的,所以平台开发者本意是要规避这种代码
h1 = h2;//这也是要规避的

代码设计者是想规避这种赋值或者拷贝,但不是通过不定义赋值函数或者拷贝构造函数就可以规避的。在item5中已经说过了,即使你没有定义他们,编译器发现后面的代码会用到,编译器也会帮你创建的。所以这里为了避免这种操作,还得让编译器不要自动创建。

禁用编译器自己创建的拷贝构造函数,拷贝赋值函数

方法1:手动添加private的拷贝构造函数,拷贝赋值函数

方法2:不用手动定义,借用编译器的默认创建的函数具有递归特性,通过统一的父类来限制

之所以推荐这个方法是因为,Scott提到的一点编码经验,像方法1的错误让他越早暴露越好。现在是链接阶段暴露,如果能提前到编译阶段暴露会更好。
更好的方法如下: 定义一个基类,让目标类继承这个基类。为了禁用目标类自动产生拷贝赋值函数,和拷贝构造函数可以利用“把基类的这两个函数”设置为private的方法。这种方法的原理是。当编译器发现目标类没有定义拷贝构造函数和拷贝赋值函数时,尝试自动创建。自动创建时需要递归调用父类的对应函数实现父类成分的操作。只要有一个父类对应拷贝赋值或者拷贝构造函数声明为private,那么编译器就会报错。

class UnCopyable 
{ 
protected: 
    Uncopyable(){};
    ~unCopyable(){};
private: 
    Uncopyable(const Uncopyable&); 
    Uncopyable& operator=(const Uncopyable&); 
}
class HomeForSale : private Uncopyable
{}

另外文中示例是让目标类private继承UCopyable。当然这里public继承也没有什么问题。 private继承和public继承的区别可以见引申章节

item6的引申

private protected public 区别

注意private protedted public的限定有两场场景,一种是对类成员数据或接口的限定,一种是对继承方式的限定。两个限定的含义是不同的。
在定义成员接口或数据的时候,有三种限定。 public protected private这三种限定词是对访问权限的限定。通俗的理解是public是完全公开的声明,这个声明是针对编译器的,意味着告诉编译器要允许任何情况的该类型接口或数据调用。无论你是在类内部调用public接口或数据,还是在类外面通过类的实例调用,编译器都可以编译通过。protected声明是告诉编译器,可以认可我家族内部的调用,家族外部的调用一律不允许。private声明是告诉编译器这个是秘密只能允许我当事人一个人调用。
换个说法可以加深下理解:

在继承方式上,public要体现is-a的关系, private要体现has-a的关系,且很少使用protected继承。这个具体在item30-item40上描述。

boost库的使用

参考文档: www.boost.org
这里简单说下linux下如何使用
1)获取boost源码, 最新的源码维护在jfrog上,不过sourceForge上也能下载到。具体见官网"getting started"系列的手册。并解压到/home/XXX/目录下
2)大部分的boost库只有头文件,头文件中包含了需要的模板和内联函数,并不需要依赖于其他库,这就为我们使用boost库提供了极大的方便,代码上只要加入#include语句,编译器设置上能找到就ok了。当然大部分并不是全部。还有一些库是有cpp文件的,还有非常少的一些也是有依赖的。
3)在代码中需要boost的地方声明头文件和必要的命名空间代码如下

#include <boost/lambda/lambda.hpp>
#include <iostream>
#include <iterator>
#include <algorithm>
int main()
{
    using namespace boost::lambda;
    typedef std::istream_iterator<int> in;
    std::for_each(in(std::cin),in(),std::cout<<(_1*3)<<"");
}
  1. 使用如下的编译命令 `g++ -I /home/XXX/boost1.77 main.cpp
上一篇下一篇

猜你喜欢

热点阅读