Effective C++ 7 模板与泛型编程 条款41-条款52

Effective C++系列文章:

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

条款41 隐式接口和编译器多态

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
模板要求w有size()、swap()等接口,这是隐式要求。

条款42 typename双重意义

在这里插入图片描述
声明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只被用来验明嵌套从属类型名称,其他名称不该有它存在
在这里插入图片描述
例外~~~!!!!!!!!!
在这里插入图片描述
总结:
在这里插入图片描述

条款43 处理模板化基类内的名称

class CompanyA{
public:
    void sendCleartext(const string& msg);
    void sendEncrypted(const string& msg);
};
class MsgInfo{};
template<typename Company>
class MsgSender{
    public:
    void sendClear(const MsgInfo &info){
        string msg;
        Company c;
        c.sendCleartext(msg);
    }
    void sendSecret(const MsgInfo& info);
};
template<typename Company>
class LoggingMsgSender: public MsgSender<Company>{
public:
    void sendClearMsg(const MsgInfo& info){
        sendClear(info);;//编译出错
    }
};

直接使用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,这个函数不存在
    }
};

在这里插入图片描述

解决办法:

  1. 在base class函数调用动作之前加上“this->”
template<typename Company>
class LoggingMsgSender: public MsgSender<Company>{
public:
    void sendClearMsg(const MsgInfo& info){
        this->sendClear(info);//OK,假设sendClear被继承下来
    }
};
  1. 使用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被继承下来
    }
};
  1. 明确指出被调用的函数位于基类中
    但这不是一个好方法(最坏的一种解决办法),因为如果被调用的是virtual函数,上述调用规则会关闭“virtual绑定行为”
template<typename Company>
class LoggingMsgSender: public MsgSender<Company>{
public:
    void sendClearMsg(const MsgInfo& info){
        MsgSender<Company>::sendClear(info);//OK,假设sendClear被继承下来
    }
};

在这里插入图片描述

条款44 将与参数无关的代码抽离templates

在这里插入图片描述
好好学模板 之后再来看这些

条款45 成员函数模板接受所有兼容类型

条款46 需要类型转换时为模板定义非成员函数

条款47 traits classes表现类型信息

条款48 认识template元编程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值