lhs(left-hand-side) rhs(right-hand-side)
“指向一个T型对象”的指针命名pt,意思是“pointer to T”
class GamePlayer{ private: enum { NumTurns = 5 };//"the enum hack"-令NumTurns成为5的一个记号名称 int scores[NumTurns]; }
如果关键字const出现在星号左边,表示被指物是常量;如果出现在星号右边,表示指针自身是常量 ;如果出现在星号两边,表示被指物和指针两者都是常量
两个成员函数如果只是常量性不同,可以被重载
当derived class对象经由一个base class指针被删除,而该base class带着一个non-virtual析构函数,其结果未有定义--实际执行时通常发生的是对象的derived成分没被销毁
vptr(virtual table pointer)
pure virtual函数导致abstract(抽象)classes -- 也就是不能被实体化(instantiated)的class
//如果close抛出异常就结束程序。通常调用abort完成: DBConn::~DBConn() { try{db.close();} catch(...){ 制作运转记录,记下对close的调用失败; std:abort();//abort--中止 } }
base class构造期间virtual函数绝不会下降到derived classes阶层
RTTI(Run-Time Type Identification,运行时类型识别)在C++中,为了支持RTTI提供了两个操作符:dynamic_cast和typeid。dynamic_cast允许运行时刻进行类型转换,从而使程序能够在一个类层次结构中安全地转化类型
由于无法使用virtual函数从base classes向下调用,在构造期间,可以藉由“令derived classes将必要的构造信息向上传递至base class构造函数”替换至而加以弥补。令此函数(必要的构造信息)为static,也就不可能意外指向“初期未成熟之derived class对象内尚未初始化的成员变量”
在复制pb所指东西之前别删除pb
copy-and-swap
把资源放进对象内,便可依赖C++的“析构函数自动调用机制”确保资源被释放
auto_ptr是个“类指针(pointer-like)对象”,也就是所谓智能指针;性质:若通过copy构造函数或copy assignment操作符复制它们,它们会变成null,而复制所得的指针将取得资源的唯一拥有权
auto_ptr和shared_ptr两者都在其析构函数内做delete而不是delete[]动作
.get()
auto_ptr和shared_ptr都提供一个get成员函数,用来执行显式转换,也就是它会返回智能指针内部的原始指针(的复件)
operator T() const 隐式转换函数
1.无构造、析构成本 2.避免slicing(对象切割)问题
对内置类型以及STL的迭代器和函数对象,值传递往往比较适当
“语法一致性”(用不用括号)、“细微划分之访问控制”、封装(改动之后的影响)
愈多东西被封装,愈少人可以看到它。而愈少人看到它,我们就有愈大的弹性去变化它,因为我们的改变仅仅直接影响看到改变的那些人和事物
private(提供封装)和其他(protected、public)不提供封装
这样做可以增加封装性、包裹弹性(packaging flexibility)和机能扩充性
result = onehalf * 2; //很好 result = 2 * onehalf; //错误!
通常我们不能够(不被允许)改变std命名空间内的任何东西,但可以(被允许)为标准templates(如swap)制造特化版本,使它专属于我们自己的classes(例如Widget) “template<>”特例化
模板分为类模板与函数模板,特化分为全特化与偏特化,函数模板不能偏特化
当打算偏特化一个function template时,惯常做法是简单地为它添加一个重载版本(但std不能再添加了)
总之,如果swap缺省实现码对你的class或者class template提供可以接受的效率,你不需要额外做任何事。任何尝试置换(swap)那种对象的人都会取得缺省版本,那将有良好的运作。 其次如果swap缺省版本实现的效率不足(那几乎总是意味着你的class或者class template,使用了某种pimpl手法)试着做以下事情: 1. 提供一个public swap成员函数,让它高效地置换你的类型的两个对象值。 2. 在你的class或者class template所在的命名空间提供一个non-member swap,并令它调用上述swap成员函数。 3. 如果你正编写一个class(而非class template),则为你的class特化std::swap,并令它调用你的swap成员函数。 最后,如果你调用swap,请确定包含一个using申明式,以便让std::swap在你的函数内曝光可见,然后不加任何namespace的修饰,赤裸裸地调用swap。
避免不必要的构造、析构成本
单一对象(例如一个类型为Derived的对象)可能拥有一个以上的地址(例如“以Base*指向它”时的地址和“以Derived指向它”时的地址),这种情况下会有个偏移量(offset)
避免返回handles(包括references、指针、迭代器)指向对象内部。遵守这个条款可增加封装性,帮助const成员函数的行为像个const,并将发生“虚吊号码牌”(dangling handles)的可能性降至最低
以对象管理资源、reset 、copy and swap
inline函数背后的整体观念是,将“对此函数的每一个调用”都以函数本体替换之。
inline意味“执行前,先将调用动作替换为被调用函数的本体”。
制作Handle class的两个办法:
1、使用pimpl idiom(pimpl,“pointer to implementation”)
2、令成为一种特殊的abstract base class(抽象基类),称为Interface class。
名称遮掩规则,即使base classes和derived classes内的函数有不同的参数类型也适用,而且不论函数是virtual或non-virtual一体适用。可以使用using声明式或转交函数(函数体内...使用Base::)达成目标
non-virtual interface(NVI)手法:令客户通过public non-virtual成员函数间接调用private virtual函数
typedef std::tr1::functionHealthGalcFunc;
virtual函数系动态绑定(dynamically bound),而缺省参数值却是静态绑定(statically bound)。
静态绑定又名前期绑定,early binding;动态绑定又名后期绑定,late binding。
静态类型 动态类型可以表现出一个对象将会有什么行为。
当复合发生于应用域内的对象之间,表现出is-a的关系;当它发生于实现域内则是表现is-implemented-in-terms-of(根据某物实现出)的关系。
Set对象可根据一个list对象实现出来。
Private继承意味implemented-in-terms-of。它通常比复合(composition)的级别低。但是当derived class需要访问protected base class的成员,或需要重新定义继承而来的virtual函数时,这么设计是合理的。
derived classes可以重新定义virtual函数,即使它们不得调用它。
EBO(empty base optimization:空白基类最优化);C++裁定凡是独立(非附属)对象都必须有非零大小
factory function(工厂函数)--创建对象
“public继承自某接口”、“private继承自某实现”
对template参数而言,接口是隐式(implicit)的,奠基于有效表达式,并不基于函数签名式。多态则是通过template具现化和函数重载解析发生于编译期。类似于“哪一个重载函数应该被调用”(发生在编译期)和“哪一个virtual函数该被绑定”(发生在运行期)之间的差异。
template内出现的名称相依于某个template参数,称之为从属名称(dependent names)。如果从属名称在class内呈嵌套状,称之为嵌套从属名称(nested dependent name)。
typename std::iterator_traits::value_type temp(*iter);//iterator_traits //"类型为T之对象所指之物的类型",如果T是vector ::iterator,temp的类型就是int //value_type被嵌套于iterator_traits 之内而T是个template参数,所以必须在它之前放置typename typedef typename std::iterator_traits ::value_type value_type;
请使用关键字typename标识嵌套从属类型名称;但不得在base class lists(基类列)或member initialization list(成员初值列)内以它作为base class修饰符。
编译器往往拒绝在templatized base classes(模板化基类)内寻找继承而来的名称,不进入base class作用域内查找。
可在derived class templates 内通过“this->”指涉base class templates内的成员名称,或藉由一个明白写出的“base class资格修饰符”完成(using)。
共性与变性分析(commonality and variability analysis)
scoped_array
scoped_array与scoped_ptr基本是一对孪生兄弟,它包装了new[]操作符(而不是new)在堆上分配的动态数组,为动态数组提供了一个代理(Proxy),保存正确地释放内存。它弥补了标准库中没有指向数组的智能指针的遗憾。 scoped_array与scoped_ptr区别基本不大,主要特点如下: 1,构造函数接受的指针p必须是new[]的结果,而不是new表达式的结果; 2,没有*、->操作符重载,scoped_array持有的不是一个普通指针; 3,析构函数使用delete[],而不是delete; 4,提供operator[]重载,可以像普通数组一样使用下标访问元素; 5,没有begin(),end()等类似容器迭代器操作函数。 scoped_array管理的是动态数组,而不是单个动态对象,通常创建方式是的。scoped_arraysa(new int[100]); //包装动态数组 既然使用重载了下标操作符那么自然可以这样使用,sa[0] = 10; 但是注意,它不提供指针运算,所以不能用数组首地+N的方式访问数组元素,如*(sa + 10) = 10;错误用法,无法通过编译 scoped_array不提供数组索引的范围检查,如果使用了超过动态数组大小的索引或是负数索引将会引发未定义行为。
但是,同一个template的不同具现体(instantiations)之间并不存在什么与生俱来的固有关系(译注:这里意指如果以带有base-derived关系的B,D两类型分别具现化某个template,产生出来的两个具现体并不带有base-derived关系)
//成员函数模板(member function templates) //泛化(generalized)copy构造函数 templateclass SmartPtr{ public: template SmartPtr(const SmartPtr& other); ... }
如果声明member templates用于“泛化copy构造函数”或“泛化assignment操作”,还是需要声明正常的copy构造函数和copy assignment操作符。
STL共有5中迭代器分类:Input、Output、forward、Bidirectional、random access
Traits classes使得“类型相关信息”在编译期可用。它们以templates和“templates特化”完成实现。p232
Template metaprogramming(TMP,模板元编程)