《C++沉思录》(Ruminations on C++)摘要

第四章类:

  • 需要构造函数,不需要构造函数的类例如其结构就是接口。
  • 数据成员最好为私有。使用成员函数设置数据成员,都心知肚明。
  • 声明类对象且不显示初始化,必须写一个无参的构造函数。
  • 最好每个构造函数初始化所有的数据成员。
  • 不是所有的类都需要析构函数,例如表示复数的类。
  • 虚析构函数用在继承且通常都是空的。
  • 类在构造函数内分配资源、除了空的虚析构函数的析构函数的类用析构函数来释放构造函数分配的资源,通常需要复制构造函数,否则会造成指针悬挂。
  • 声明复制构造函数(可能还有赋值操作符)为私有,用户和程序员就不能复制类的对象。
  • 赋值操作符。私有化用户不能设置类的对象,以 return *this;结束保证与内建的复制操作符一致。
  • 记得在复制构造函数和赋值操作符的参数类型中加上const。

第五章代理类

  • 只有纯虚函数的类,不会有对象,即不存在;从此类派生出来的类才能够实例化。
  • C++使用虚函数处理未知类型的对象方法。
  • 定义一个行为和基类对象相似,、而又潜在表示了所有继承自基类的对象东西,我们把这种类的对象叫做代理。在类中定义一个纯虚函数,然后该类的指针。
  • 代理的类能让我们在一个容器中存储类型不同但相互关联的对象。

句柄:避免不必要的对象复制

  • 从效果上说,handle就是一种只包含单个对象的容器。
  • 获取底层对象(Point)的地址:
    Point* addr = h.operator->();
    所以要把真实地址隐蔽起来,就必须避免使用operator->,而且必须明确地选择让我们的handle类支持哪些Point操作。
  • 使用引用计数实现:新的类UPoint来容纳一个引用计数和一个Point对象,其所有成员都设置为private,并且句柄类声明为友元friend class Handle;
  • copy on write写时复制:只有在绝对必要时才进行复制
    只是针对可变对象的一种优化技巧。实现了值语义。
    如果永远不需要写入,则永远不需要写时复制。

虚函数

  • 虚函数不总是适用:
  • 有时会带来很大的消耗
  • 不总是提供所需的行为
  • 有时写一个类时,可能不想考虑派生问题
  • 必须使用虚析构函数:
    删除一个表面指向基类对象,实际却是指向派生类对象的指针

十二章 设计容器类

  • 结构体实现值语义:复制完成后,两个变量都有这个值的独立副本
    数组实现引用语义:复制完成后,两个变量丢引用同一个底层对象

  • 把一个对象放入到容器中时,应该复制该对象

  • 指针和下标的区别:

  • 在下标的例子中,下标值本身就有意义,而与它是否用作下标无关

  • 在指针的例子中,要访问容器的元素没有必要知道容器的标识:指针自身就包含了所有必要的信息

  • 下标容易理解,指针效率更高

  • 对内建数组使用指针比使用下标要方便得多,因为使用下标还有知道使用哪个数组

  • 在类似数组的类中使用指针会带来一个缺陷:改变这样的类的实现或者增加它的操作都会突然使指向它的元素的指针失效


  • 泛型算法:对于所操作的数据结构的细节信息,只加入最低限度的了解。
  • 5种迭代器
  • 输入迭代器:能够按照某个预先规定的顺序读(不是写)序列中的元素
  • 输出迭代器:可以写操作。如果p是一个输出迭代器,那么我们应该被允许改变*p,但是不一定允许读取
  • 前向迭代器:输入迭代器+输出迭代器
  • 双向迭代器:前向迭代器 + operator–
  • 随机存取迭代器:折半查找。解决类似指向链表元素的指针的类的头一个元素,到达第1000个元素(不能使用执行1000次++p的方法)
  • 输出迭代器限制:每次由输出迭代器表示定位时都必须给迭代器赋一个值,而且只能赋一次
    输入迭代器限制:如果迭代器增加到超过了某个特定的输入值,那么这个值将再也不能被访问了
  • 当类型int*的值指向数组的某个元素的值是,这个类型既可以用作输入迭代器,又可以用作输出迭代器。
  • 输入比输出难:1.输出迭代器一般不需要相互比较。输入迭代器必须实现比较操作才能判断是否到达了文件尾部。2.如果不进行尝试性的读取,就不可能判断是否已经到达文件尾部。但读取值是很耗费系统资源的,所以只有在绝对需要这样做时才不得已而为之

20章 迭代器配接器:

  • 在一个(可多可少)任意的数据结构中进行线性查找,如果不存在,返回最后一个元素:

    Templete<class T, class X>
    T find(T start, T beyond, const X& x)
    {
    while (start != beyond && *start != x)
    ++start;
    return start;
    }

  • 类似循环赋值时,判断条件最好不要<=和>=,拿<和>代替,防止指向被禁止的值,导致不能保持原有的对称性


函数对象

  • C/C++不可能有函数类型的变量,所有对函数指针的调用都等价于对这个指针所指向的函数的调用。
  • C++函数的总存储空间在程序执行之前就固定了。一旦程序开始运行,就无法创建新函数(可能会通过提供动态链接库的某种形式改变这个限制,但没正确应用于语言中)。C++不支持嵌套函数。
  • 包含一个operator()成员函数,就可以把类对象当作函数来使用。

  • 函数对象:class里面有构造函数,operator()
    可以将一个函数和一个值捆绑到单个实体中。
  • 库:如果某一组类的设计和实现是希望得到广泛应用。
  • 隐藏实现:给我们带来了一定的灵活性,方便以后根据需要修改实现。适当隐藏实现也是帮助防止用户出错的重要方法。
  • cout<<endl; 等价于 cout<<"\n"<<flush;
  • cout表示一个输出文件
  • 当把数组赋给其自身会发生Bug:
    源数组的元素会被删除掉,接着又会非法地进行复制。
    显示检查自我复制清楚Bug代码
Array& operator=(const Array& a)
{
	if(this != &a)
	{
		delete[] data;
		init(a.data, a.sz);
	}
	return *this;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值