Effective C++笔记 —— 第七章

本文探讨了C++中如何通过不同template参数具现化functiontemplates实现编译器多态,解释了从属名称与嵌套从属名称的概念,以及在classtemplate中调用基类函数的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  1. 以不同template参数具现化function templates会导致调用不同的函数,这便是所谓的编译器多态;哪一个重载函数被调用也是发生在编译期
  2. 如果template内出现的名称如果相依于某个template参数,称之为从属名称。如果从属名称在class内呈嵌套状,我们称它为嵌套从属名称,如果解析器在template中遭遇一个嵌套从属名称,它便假设这个名称不是个类型,除非你告诉它是。比如 C::const_iteator* x;需要在前面加上typename;但是又两个例外,typename不可以出现在八色 classes list内的嵌套从属名称之前,也不可以在member initialization list中作为base class修饰符
  3. 可在derived class template内通过“this->”指涉base class template内的成员名称,或者通过using
    class CompantA
    {
    public:
    ...
    void sendCleartext(const std::string& msg);
    void sendEncrypted(const std::string& msg);
    ...
    };
    ```javascript
    class CompantB
    {
    public:
    ...
    void sendCleartext(const std::string& msg);
    void sendEncrypted(const std::string& msg);
    ...
    };
    ...
    class MsgInfo{...}; //这个class用来保存信息,以备将来产生信息
    template<typename Company>
    class MsgSender{
    public:
    ...
    void sendClear(const MsgInfo& info)
    {
    std::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);    //调用base class函数;这段代码无法通过编译
    }
    };
    
    当编译器遭遇class template LoggingMsgSender定义式时,并不知道它继承什么样的class,当然它继承的是MsgSender< Company >,但其中的Company是个参数,不到LoggingMsgSender被具现化无法确切知道它是什么。而如果不知道Company是什么,就无法知道class MsgSender< Company >是否有个sendClear函数
    class CompanyZ
    {
    public:
    ...
    void sendEncrypted(const std::string& msg);  //这个函数不提供sendCleartext函数
    };
    
    template<>
    class MsgSender<CompanyZ>    //一个全特化版本的MsgSender,差别只是它删掉了sendClear
    {
    public:
    ...
    void sendSecret(const MsgInfo& info)
    {...}
    };
    
    这就是为什么C++拒绝这个调用的原因:它知道base class template有可能被特化,而特化版本可能不提供和一般性template相同的接口
    有三个办法,第一是在base class函数调用动作之前加上“this->”:
    template<typename Company>
    class LoggingMsgSender:public MsgSender<Company>
    {
    public:
    ...
    void sendClearMsg(const MsgInfo& info)
    {
    this->sendClear(info);    
    }
    };
    
    第二个是使用using声明式
    template<typename Company>
    class LoggingMsgSender:public MsgSender<Company>
    {
    public:
    using MsgSender<Company>::sendClear;
    ...
    void sendClearMsg(const MsgInfo& info)
    {
    sendClear(info);    
    }
    };
    
    第三个做法是明白指出被调用的函数位于base class内:
    template<typename Company>
    class LoggingMsgSender:public MsgSender<Company>
    {
    public:
    ...
    void sendClearMsg(const MsgInfo& info)
    {
    MsgSender<Company>::sendClear(info);    
    }
    };
    
    但是这往往不令人满意,如果被调用的是virtual函数,上述的明确资格修饰会关闭“virtual绑定行为”
  4. template实参推导过程中从不将隐式类型转换函数纳入考虑,当我们编写一个class template,而它所提供之与此template相关的函数支持所有参数之隐式类型转换时,请将那些函数定义为class template内部的friend 函数
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值