清明时节雨纷纷,转眼已经到清明,来杭许久,入职也近两周。上班加班太多,学习时断时续。其实,已经转战客户端开发的我,略显迷茫。这本书啊,明天看完吧!!!
减少不必要的构造、析构(最好定义和赋值放到一块)。
C++四中转换类型:
const_cast(expression)
dynamic_cast(expression)
reinterpret_cast(expression)
static_cast(expression)
特别是避免使用dynamic_cast,底层实现复杂,效率太慢。可采用下面方式:
typedef std::vector<std::tr1::shared_ptr > VPSW;
VPSW winPtrs;
...
for (VPSW::iterator iter = winPtrs.begin(); iter != winPtrs.end(); ++iter)
(*iter)->blink( );
或基类声明virtual函数。
调用同名基类方法,如果采用下面的操作只是副本的操作:
static_cast(*this).onResize( );
应该改写为:
Window::onResize();
会破坏封装性,也可能导致悬挂指针(悬挂handles)。
异常安全就像怀孕,要么没怀上(不安全),要么怀上了(安全)。
“异常安全函数”即使发生异常也不会有资源泄漏或允许任何数据结构败坏。在这个基础下,它有3个级别:基本保证、强烈保证、不抛异常。
基本保证:
class PrettyMenu
{
...
std::tr1::shared_ptr bgImage;
...
};
void PrettyMenu::changeBackground(std::istream& imgSrc) {
Lock ml(&mutex);
bgImage.reset(new Image(imgSrc));
++imageChanges;
}
“强烈保证”往往可以通过copy-and-swap实现:
struct PMImpl {
std::tr1::shared_ptr bgImage;
int imageChanges;
};
class PrettyMenu
{
...
private:
Mutex mutex;
std::tr1::shared_ptr pImpl;
};
void PrettyMenu::changeBackground(std::istream& imgSrc) {
using std::swap;
Lock ml(&mutex);
std::tr1::shared_ptr<PMImpl> pNew(new PMImpl(*pImpl));
pNew->bgImage.reset(new Image(imgSrc));
++pNew->imageChanges;
swap(pImpl, pNew);
}
ps:内置类型和指针的操作就绝不会抛出异常
讲解了编译器如何对待内联函数。
相依于声明式,不要相依于定义式。
两个手段:Handle classes(impl对象提供服务)和Interface classes。
public继承意味着is-a。适用于base class身上的每一个函数也一定适用于derived class。
Names in derived classes hide names in base classes.
To make hidden names visible again, employ using declarations or forwarding functions.
class Drive{
public:
using Base::f1; //using 声明式
void f1(int);
}
class Drive{
public:
void f1(){
Base::f1(); //转交函数
}
}
class Shape
{
public:
virtual void draw() const = 0;
virtual void error(const std::string& msg);
int objectID() const;
...
};
纯虚函数:提供接口继承 Drived class必须实现纯虚函数,但同时可以给纯虚函数提供定义
pure virtual functions must be redeclared in concrete derived classes, but they may also have implementations of their own.
虚函数:提供接口继承和默认的实现继承
非虚函数:提供了接口继承和强制的实现继承
non-virtual interface(NVI)
class GameCharacter
{
public:
int healthValue() const
{
... //事前工作
int retVal = doHealthValue();
... //事后工作
return retVal;
}
...
private: //protected、public亦可
virtual int doHealthValue() const {
...
}
};
class GameCharacter; // forward declaration
int defaultHealthCalc(const GameCharacter& gc);
class GameCharacter
{
public:
typedef int (*HealthCalcFunc)(const GameCharacter&);
explicit GameCharacter(HealthCalcFunc hcf = defaultHealthCalc)
: healthFunc(hcf )
{}
int healthValue() const
{ return healthFunc(*this); }
...
private:
HealthCalcFunc healthFunc;
};
这个东西boost库里也有,C++11也有此特性(陈硕极力推崇之)
class GameCharacter
{
public:
typedef std::tr1::function HealthCalcFunc;
explicit GameCharacter(HealthCalcFunc hcf = defaultHealthCalc)
: healthFunc(hcf )
{}
int healthValue() const
{ return healthFunc(*this); }
...
private:
HealthCalcFunc healthFunc;
};
short calcHealth(const GameCharacter&);
struct HealthCalculator {
int operator()(const GameCharacter&) const { ... }
};
class GameLevel {
public:
float health(const GameCharacter&) const;
};
class EvilBadGuy: public GameCharacter {
...
};
class EyeCandyCharacter: public GameCharacter {
...
};
EvilBadGuy ebg1(calcHealth);
EyeCandyCharacter ecc1(HealthCalculator());
GameLevel currentLevel; …
EvilBadGuy ebg2(std::tr1::bind(&GameLevel::health, currentLevel, _1));
这就是一般书籍上介绍的策略模式。
否则何必定义为non-virtual函数。
缺省参数是静态绑定编译的,也就是说实际上只会用基类的缺省值。
组合降低耦合,属于设计原则之一。
本条里实现的Set算是适配器的实现方式吧。
private继承是”根据某物实现出“
class Widget: private Timer
{
private:
virtual void onTick() const;
...
};
✦ Private inheritance means is-implemented-in-terms of. It’s usually inferior to composition, but it makes sense when a derived class needs access to protected base class members or needs to redefine inherited virtual functions. //访问保护成员或重定义虚函数
✦ Unlike composition, private inheritance can enable the empty base optimization. This can be important for library developers who strive to minimize object sizes. //空白基类最优化
采用组合方式更好:
class Widget
{
private:
class WidgetTimer: public Timer
{
public:
virtual void onTick() const;
...
};
WidgetTimer timer;
...
};
多重继承使用场景:public继承某个Interface class,private继承某个协助实现的class。
对模板而言,接口是隐式的,多态表现在template具象化和函数重载解析,发生在编译期。
声明template参数时,前缀关键字class和typename可以互换
使用typename标识嵌套从属类型名称(但最终解释权属于编译器)
typename C::const_iterator iter(container.begin());
由于存在模板特例化的可能,编译器并不能直接识别模板化基类内的名称:
template
class LoggingMsgSender: public MsgSender
{
public:
void sendClearMsg(const MsgInfo& info) {
sendClear(info); //sendClear是基类方法,但这样编译会报错
}
...
};
可以采用:
this->sendClear(info); //方法一:使用this
using MsgSender::sendClear; //方法二:使用using
MsgSender::sendClear(info); //方法三:使用作用域运算符
非类型模板参数造成的代码膨胀:以函数参数或者成员变量替换
template<typename T> class SquareMatrixBase
{
protected:
...
void invert(std::size_t matrixSize);
};
template<typename T, std::size_t n>
class SquareMatrix: private SquareMatrixBase
{
private:
using SquareMatrixBase::invert;
public:
void invert() { invert(n); } //以函数参数代替模板参数
};
模板类的继承实现——成员函数模板
template<class T>
class shared_ptr
{
public:
shared_ptr(shared_ptr const& r);
template<class Y>
shared_ptr(shared_ptr const& r); //成员函数模板
shared_ptr& operator=(shared_ptr const& r);
template<class Y>
shared_ptr& operator=(shared_ptr const& r); //成员函数模板
};
成员函数模板是为了泛化,当“泛化拷贝构造函数”和“泛化的赋值构造”时,仍然需要声明正常的拷贝构造函数和赋值构造函数(不改变C++特性)
这是与普通类条款24对应的模板类条款。
但不能在类外直接定义(类型推导不可行),其形式只能是友元的定义和声明在一起,如下:
templateT>
class Rational {
public:
...
friend const Rational operator*(const Rational& lhs, const Rational& rhs)
{
return Rational(lhs.numerator() * rhs.numerator(), lhs.denominator() * rhs.denominator());
}
};
特性萃取技术(对我而言是新知识,作者讲到的实现真是令人叹为观止)
template < ... >
class list {
public:
class iterator {
public:
typedef bidirectional_iterator_tag iterator_category;
...
};
};
struct iterator_traits {
typedef typename IterT::iterator_category iterator_category;
...
};
templateT> // partial template specialization struct iterator_traits<T*> // for built-in pointer types
{
typedef random_access_iterator_tag iterator_category;
};
template
struct Factorial {
enum { value = n * Factorial1>::value };
};
template<>
{
enum{value=1};
};
略
tr1简直就是c++11的新特性!
略
终于看完了,杂项其实很重要,但的确需要大把时间去看,我也没罗列一些东西,暂且不提。
第五章的实现内容,主要是从高效的角度阐述实现,譬如定义延后、内联、少用转换。其中异常安全值得细读。
第六章偏重于继承的讲解,其实暗带多态。继承和多态是一对难兄难弟,多态其实就是面向接口编程,继承一直为人诟病,组合也早成为其后继者。第35条取代虚函数的方法很好。
第七章看的最慢,也最难懂(我没写过类模板)。感觉还是偏重理论而非工程了,后半段倒是有点意思,譬如第47条。