Part7 模板与泛型编程 Templates and Generic Programming

  • Rule41: 了解隐式接口和编译期多态
    understand implicit interfaces and compile-time polymorphism.

面向对象编程总是以显式接口(explicit interfaces)和运行期多态(runtime polymorphism)解决问题。

请记住:
(1)classes和Template都支持接口和多态
(2)对class而言接口是显式的,以函数签名为中心,如下面直接的函数签名为定义:

Class Widget
{
 public:
     Wigdet();
    virtual~ Widget();
    virtual std::size_t size() const;
    virtual void normalize();
    void swap(Widget& other);
}。

多态则是通过virtual函数发生于运行期。
(3)对Template参数而言,接口是隐式的,奠基与有效表达式。多态则是通过Template具现化和函数重载解析发生于编译期。

  • Rule42: 了解typename的双重意义
    understand the two meanings of typename.
    一种常用的做法是在定义模板类或模板方法中使用。
    还有一种情况如下描述:
template<typename C>
void print2nd(const C& container)
{
if(container.size >=2)
    {
    C::const_iterator iter(container.begin());//编译通不过
    ++iter;
    int value = *iter;
    std::out<<value;
    }
}

这种写法编译不能通过,因为编译器默认情况下不会将“嵌套从属名称”视为一种类型,除非用户自己指定。。。
指定方法也比较固定:

typename C::const_iterator iter(container.begin());
  • Rule43:学习处理模板化基类内的名称
    Know how to access names in templatized base classes.
    先看如下例子,CompanyA和CompanyB提供了两种相同的方法,根据不同公司处理的算法不同,MsgSender是一个消息发送类,可以发送公司的消息,明文形式或者加密形式。
#include <iostream>
using namespace std;

class CompanyA{
public:
    void sendCleartext(const std::string& msg){};
    void sendEncrypted(const std::string& msg){};
};
class CompanyB{
public:
    void sendCleartext(const std::string& msg){};
    void sendEncrypted(const std::string& msg){};
};

class MsgInfo{};

template<typename Company>
class MsgSender{
public:

    void sendClear(const MsgInfo& info)
    {
    std::string msg;
    //这里,根据info产生信息
    Company c;
    c.sendCleartext(msg);
    }
    void sendSecret(const MsgInfo& info)
    {
        std::string msg;
        //这里,根据info产生信息
        Company c;
        c.sendEncrypted(msg);
    }

};

int _tmain(int argc, _TCHAR* argv[])
{
    MsgSender<CompanyA> ca;
    ca.sendClear(MsgInfo());
    getchar();
    return 0;
}

以上代码能正常进行编译运行。
现在假设需要在发送信息的时候增加日志记录的附加功能,我们继承MsgSender,如下所示。

template<typename Company>
class LoggingMsgSender:public MsgSender<Company>{
public:

    void sendClearMsg(const MsgInfo& info)
    {
        //将“传送前”的信息写至log

        //调用base函数
        sendClear(info);

        //将“传送后”的信息写至log;
    }
    void sendSecretMsg(const MsgInfo& info)
    {
        //将“传送前”的信息写至log

        //调用base函数
        sendSecret(info);

        //将“传送后”的信息写至log;
    }

};

Effective C++指出上述代码在某些严格编译器上会编译出错,提示找不到标志符 “sendClear”和“sendSecret”。 理应是可以的,因为它就是继承自MsgSender,这两个方法本身就存在。本人在VS 2010 IDE中编写了上述代码,能够正常运行。
保险起见,作者给出了三种解决方法:
第一种是在base class函数调用动作之前加上 this->。如下形式:
this->sendClear(info);
第二种是使用using声明式,
如下: using Msgsender<Company>::sendClear //明确告诉编译器,请它假设sendClear位于base class内。
这种做法是在有的编译器不进入base class作用域内查找,于是我们通过using告诉它,请它那么做。
第三种做法是,明白指出被调用的函数位于base class内。
Msgsender<Company>::sendClear(info) //OK,假设sendClear将被继承下来
但这种方法往往是不让人满意的,因为如果被调用的是virtual函数,上述的声明方法会关闭“virtual绑定行为”

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值