Effective C++ 1自己习惯C++ 条款01-条款04 Effective C++ 2 构造/析构/赋值运算 条款5-条款12 Effective C++ 3 资源管理 条款13-条款17 Effective C++ 4 设计与声明 条款18-条款25 Effective C++ 5 实现 条款26-条款31 Effective C++ 6 继承与面向对象设计 条款32-条款40 Effective C++ 7 模板与泛型编程 条款41-条款52 Effective C++ 8 杂项讨论 条款53-条款55
模板要求w有size()、swap()等接口,这是隐式要求。
声明template参数时,不论关键字class或typename,用法和作用没有不同;
有的只能用typename
template<class C> void print2nd(const C container){ if(container.size() >= 2){ C::const_iterator iter(container.begin());//编译出错,解析 C::const_iterator时出问题 ++iter; int value = *iter; cout<<value; } }从属名称(dependent names): template中出现的名称相依与某个template参数 嵌套从属名称(nested dependent name):从属名称在class中呈嵌套状 例如C::const_iterator(它还是个嵌套从属类型名称,也就是个嵌套从属名称并且指某个类型。 非从属名称(non-dependent name):不依赖任何template参数的名称,例如int 嵌套从属名称可能导致解析困难,例如使用
template<typename C> void print2nd(const C& container){ C::const_iterator *x; }解析时不知道C::const_iterator是个类型名称还是个变量名称(就是两个变量相乘) 缺省情况下嵌套从属名称不是类型 template void print2nd(const C container){ if(container.size() >= 2){ C::const_iterator iter(container.begin()); … } } 编译出错,解析 C::const_iterator被默认解析为一个变量名。 一般性规则:任何时候想要在template中指涉(refer to)一个嵌套从属类型名称,就必须在紧邻它的前一个位置放上关键字typename, typename只被用来验明嵌套从属类型名称,其他名称不该有它存在 例外~~~!!!!!!!!! 总结:
直接使用SendClear(info)编译出错
class CompanyZ{ public: void sendEncrypted(const string& ms); }假设有个class CompanyZ坚持使用加密通讯,这意味着一般的MsgSender template不适合,因为那个template提供了一个sendClear函数,这对CompanyZ不合理,所以针对CompanyZ进行特化:
template<> class MsgSender<CompanyZ>{ //一个全特化的MsgSender,它和一般template相同,差别在于它删掉了sendClear public: void sendSecret(const MsgInfo& info); } template<typename Company> class LoggingMsgSender: public MsgSender<Company>{ public: void sendClearMsg(const MsgInfo& info){ sendClear(info);;//如果Company==CompanyZ,这个函数不存在 } };解决办法:
在base class函数调用动作之前加上“this->” template<typename Company> class LoggingMsgSender: public MsgSender<Company>{ public: void sendClearMsg(const MsgInfo& info){ this->sendClear(info);//OK,假设sendClear被继承下来 } }; 使用using声明式 条款33说:使用using表达式将被掩盖的基类名称代入一个继承类作用域中,但是这里的情况不是基类名称被继承类覆盖,而是编译器不进入基类作用域内查找,于是我们通过using告诉它,请它这么做。 template<typename Company> class LoggingMsgSender: public MsgSender<Company>{ public: using MsgSender<Company>:sendClear;//告诉编译器,请它假设sendClear位于base class内 void sendClearMsg(const MsgInfo& info){ sendClear(info);//OK,假设sendClear被继承下来 } }; 明确指出被调用的函数位于基类中 但这不是一个好方法(最坏的一种解决办法),因为如果被调用的是virtual函数,上述调用规则会关闭“virtual绑定行为” template<typename Company> class LoggingMsgSender: public MsgSender<Company>{ public: void sendClearMsg(const MsgInfo& info){ MsgSender<Company>::sendClear(info);//OK,假设sendClear被继承下来 } };好好学模板 之后再来看这些