《Effective C++中文版,第三版》读书笔记7

这篇具有很好参考价值的文章主要介绍了《Effective C++中文版,第三版》读书笔记7。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

条款41: 了解隐式接口和编译期多态

隐式接口:

​ 仅仅由一组有效表达式构成,表达式自身可能看起来很复杂,但它们要求的约束条件一般而言相当直接而明确。

显式接口:

​ 通常由函数的签名式(也就是函数名称、参数类型、返回类型)构成

​ 在源码中明确可见。

#include <iostream>

// 个人感觉隐式和显式接口只是站在了不同的角度看一个类的接口。
// 站在类的角度:
// 类中定义的接口是显示的

// 站在template 参数的这个角色的角度而言:接口是隐式的,就是个表达式。
// (换个说法:这个隐式接口其实就是隐藏条件的说法,如果某个类想要作为template的参数,它必须有满足template 表达式要求的接口)
class Base
{
    public:
        ~Base() = default;
        virtual void myPrint() = 0;
        int size() {return 111;}
};

class Derived: public Base
{
    public:
    Derived() {}
    ~Derived() = default;
    virtual void myPrint()
    {
        std::cout << "Derived cout!!!" <<std::endl;
    }
};

void myPrint1(Derived &dd)
{
    dd.myPrint();
}

template<typename T>
void myPrint2(T t)
{
    t.myPrint();
    t.size();
}

int main(int argc, char const *argv[])
{
    Derived dd;
    myPrint1(dd);
    myPrint2(dd);
    return 0;
}

编译期多态:

在编译时才能确定具体调用哪个函数

#include <iostream>
#include <string>

// 编译期多态,个人理解就是:在编译时存在多个选择,根据参数类型的不同调用不同的函数。
// 对于重载: 在编译时根据参数的不同,选择不同的函数。(这些个函数已经存在,选一个心仪的)
// 对于function templates: 在编译期,根据不同的template参数具现出不同的函数(函数还没有,根据参数不同,现生成一个心仪的)
template <typename T>
T max1(const T &a, const T &b)
{
    return a > b ? a : b;
}

int min1(const int &a, const int &b)
{
    std::cout << "int min" << std::endl;
    return a < b ? a : b;
}

std::string min1(const std::string &a, const std::string &b)
{
    std::cout << "string min" << std::endl;
    return a < b ? a : b;
}

int main(int argc, char const *argv[])
{
    int a = 11, b = 12;
    std::string a1("hello world"), b1("hello");

    std::cout << max1(a, b) << std::endl;
    std::cout << max1(a1, b1) << std::endl;
    std::cout << min1(a, b) << std::endl;
    std::cout << min1(a1, b1) << std::endl;
    return 0;
}

运行期多态:

在运行时才知道待用哪个函数。

#include <iostream>

// 运行时多态演示代码
class Base
{
    public:
        ~Base() = default;
        virtual void myPrint() = 0;
};

class Derived: public Base
{
    public:
    Derived() {}
    ~Derived() = default;
    virtual void myPrint()
    {
        std::cout << "Derived cout!!!" <<std::endl;
    }
};


int main(int argc, char const *argv[])
{
    Base *pb = new Derived;

    // 程序运行的时候,才能明确调用的时Derived的myPrint()
    pb->myPrint();
    delete pb;
    return 0;
}

请记住:

classes 和template都支持接口和多态

对于classes而言接口是显式的,以函数签名为中心。多态则是通过virtual函数发生于运行期

对于template参数而言,接口是隐式的,基于有效表达式。多态则是通过template具现化和函数重载解析发生于编译器

条款42:了解typename的双重意义

请记住:

声明template参数时,前缀关键字class和typename可互换

请使用关键字表示嵌套从属类型名称;但不得在base class lists(基类列)或member initialization list(成员初值列)内以它作为base class修饰符。

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

请记住:

​ 可在derived class templates内通过“this->”指涉base class templates内的成员名称,或藉由一个明白写出的“base class 资格修饰符”完成

写一段:

#include <iostream>
#include <string>
class CompanyA
{
public:
    CompanyA() {}
    ~CompanyA() = default;
    void sendClearText(const std::string &msg)
    {
        std::cout << "company A sendEncrypted msg = " + msg << std::endl;
    }

    void sendEncrypted(const std::string &msg)
    {
        std::cout << "company A sendEncrypted msg = " + msg << std::endl;
    }
};

class CompanyB
{
public:
    CompanyB() {}
    ~CompanyB() = default;
    void sendClearText(const std::string &msg)
    {
        std::cout << "company B sendEncrypted msg = " + msg << std::endl;
    }

    void sendEncrypted(const std::string &msg)
    {
        std::cout << "company B sendEncrypted msg = " + msg << std::endl;
    }
};

class MsgInfo
{
public:
    MsgInfo(const std::string &inmsg) : msg(inmsg) {}
    ~MsgInfo() = default;
    std::string getMsg() const
    {
        return msg;
    }

private:
    std::string msg;
};

template <typename Company>
class MsgSender
{
public:
    MsgSender() {}
    ~MsgSender() = default;
    void sendClear(const MsgInfo &info)
    {
        std::string msg = info.getMsg();
        Company c;
        c.sendClearText(msg);
    }

    void sendSecret(const MsgInfo &info)
    {
        std::string msg = info.getMsg();
        Company c;
        c.sendEncrypted(msg);
    }
};

// 以template为基类定义子类
template <typename Company>
class LoggingMsgSender : public MsgSender<Company>
{
public:
    LoggingMsgSender() {}
    ~LoggingMsgSender() = default;

    // 解决方案3:使用using声明式,假设sendClear在基类
    // using MsgSender<Company>::sendClear;
    void sendClearMsg(const MsgInfo &info)
    {
        std::cout << "adasd" << std::endl;
        // g++报错: there are no arguments to 'sendClear' that depend on a template parameter,
        // so a declaration of 'sendClear' must be available
        // 解决方案1:使用编译参数:“-fpermissive”,使用该参数后从报错变成了告警。
        // 解决方案2:使用this
        // this->sendClear(info);
        sendClear(info); //LoggingMsgSender在被实例化之前不知道sendClear在哪里。编译器也不会到base classes内查找。
        // 解决方案4: 明确指出被调用函数位于基类中(这个方案不推荐使用),如果sendClear是一个virtual,这样会关闭“virtual 绑定行为”
        // MsgSender<Company>::sendClear(info);
        std::cout << "adasdfffff" << std::endl;
    }
};

class CompanyZ
{
public:
    CompanyZ() {}
    ~CompanyZ() = default;

    void sendEncrypted(const std::string &msg)
    {
        std::cout << "company Z sendEncrypted msg = " + msg << std::endl;
    }
};

// template<>这个不是template也不是标准class,而是个特化版的MsgSender template,在template实参是CompanyZ时候使用。
// 这就是模板全特化
template <>
class MsgSender<CompanyZ>
{
public:
    MsgSender() {}
    ~MsgSender() = default;
    void sendSecret(const MsgInfo &info)
    {
        std::string msg = info.getMsg();
        CompanyZ c;
        c.sendEncrypted(msg);
    }
};

int main(int argc, char const *argv[])
{
    LoggingMsgSender<CompanyA> mca;
    mca.sendClear(std::string("hello"));
    mca.sendSecret(std::string("hello"));

    LoggingMsgSender<CompanyB> mcb;
    mcb.sendClear(std::string("hello"));
    mcb.sendSecret(std::string("hello"));

    // 模板全特化:针对某一个类型的全面特化。
    LoggingMsgSender<CompanyZ> mcz;

    // 特化版的MsgSender template中没有提供sendClear
    // mcz.sendClear(std::string("hello")); // 编译报错
    mcz.sendSecret(std::string("world"));
    return 0;
}

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

请记住:

​ template生成多个 classes和多个函数,所以任何template代码都不应该于某个造成膨胀的template参数产生相依关系。

​ 因非模板参数而造成的代码膨胀,往往可以消除。做法是以函数参数或class成员变量替换template参数。

​ 因类型参数(type parameters)造成的代码膨胀,往往可以降低,做法是让带有完全相同二进制表述的具象类型实现共享代码。

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

请记住:

​ 请使用member function templates 生成“可接受所有兼容类型”的函数

​ 如果你声明member templates 用于“泛化构造”或“泛化assignment”,你还需要声明正常的copy构造函数和copy assignment函数。

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

请记住:

​ 当我们编写一个class template,而它所提供的“与此template相关”函数支持“所有参数之隐式转换”时,请将那些函数定义为“class template内部的friend函数”。

条款47:请使用traits class 表现类型信息

请记住:

​ Traits classes使得“类型相关信息”在编译期可用。它们以templates和“”完成实现

​ 整合重载技术后,traits classes有可能在编译期对类型执行if…else测试。

条款48:认识template元编程

这个可能太高阶了,目前知道有这么个东西就行。光靠这里去理解可能有点难。

什么是模板元编程(Template metaprogramming- TMP)?

编写template-base C++程序并执行于编译期的过程

TMP是被发现而不是发明出来的。

使用TMP的好处?

1.它让事情更容易

2.某些错误可以在编译期就找出来

3.可能在每一个方面都高效:较小的可执行文件、较短的运行期、较少的内存需求

缺点:

​ 编译时间变长了

难点:

​ 语法不直观,支持工具不充分。

请记住:

​ TMP可将工作由运行期迁移到编译期,从而实现早期错误侦测和更高的执行效率

​ TMP可被用来生成“基于政策选择组合”(based on combinations of policy choices)的客户定制代码,也可用来避免生成对某些特殊类型并不适合的代码。文章来源地址https://www.toymoban.com/news/detail-704068.html

到了这里,关于《Effective C++中文版,第三版》读书笔记7的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 《斯坦福数据挖掘教程·第三版》读书笔记(英文版) Chapter 2 MapReduce and the New Software Stack

    来源:《斯坦福数据挖掘教程·第三版》对应的公开英文书和PPT Computing cluster means large collections of commodity hardware, including conventional processors (“ compute nodes ”) connected by Ethernet cables or inexpensive switches . The software stack begins with a new form of file system, called a “ distributed file system ,”

    2024年02月04日
    浏览(37)
  • 《Effective C++》第三版-1. 让自己习惯C++(Accustoming Yourself to C++)

    目录 条款01:视C++为一个语言联邦(View C++ as a federation of languages) 条款02:尽量以const、enum、inline替换#define(Prefer consts, enums, and inlines to #define) 替换原因 两种特殊常量 形似函数的宏 条款03:尽可能使用const(Use const whenever possible) const和指针 const成员函数 在const和non-co

    2024年04月28日
    浏览(26)
  • 笔记软件Notability mac中文版软件功能

    Notability mac是一款帮助用户备注文件的得力工具,Notability Mac版可用于注释文稿、草拟想法、录制演讲、记录备注等。它将键入、手写、录音和照片结合在一起,便于您根据需要创建相应的备注。 Mac Notability mac中文版软件功能 将手写,照片和打字结合在一起,使您的项目焕发

    2024年02月07日
    浏览(36)
  • 《Effective C++》第三版-2. 构造析构赋值运算(Constructors,Destructors,and Assignment Operators)

    目录 条款05:了解C++默默编写并调用哪些函数(Know what functions C++ silently writes and calls) 自动生成的函数 举例说明 条款06:若不想使用编译器自动生成的函数,就该明确拒绝(Explicitly disallow the use of compiler-generated functions you do not want) 条款07:为多态基类声明virtual析构函数(

    2024年04月28日
    浏览(34)
  • c++ primer中文版第五版作业第七章

    仓库地址 7.1 7.2 7.3 7.4 7.5 7.6 7.7 7.8   因为 read 函数会修改其数值而 print 函数不会。 7.9 7.10   从 cin 中读如数据到 data1 ,如果成功就再从 cin 中读取数据到 data2 ,如果成功就执行 if 后的语句。 7.11 7.12 7.13 7.14 7.15 7.16    没有 限制,需要在整个程序内可被访问的接口部分

    2024年03月09日
    浏览(49)
  • ChatGPT prompt engineering (中文版)笔记 |吴恩达ChatGPT 提示工程

    出处:https://download.csdn.net/download/weixin_45766780/87746321 感谢中文版翻译https://github.com/datawhalechina/prompt-engineering-for-developers/tree/main/content 国内 == 需要对openapi的endpoint做一个反向代理,并修改本地openai包的源代码== 如下图: completion 原则一:编写清晰、具体的指令 你应该通过提供

    2024年02月03日
    浏览(42)
  • 惠普台式笔记本一体机电脑BIOS中文版对照图解介绍

    注意VT 默认是不开启的。 太简陋了,只有一个风扇转速连个温度显示都没有。 可以设置定时开机的具体到分钟。 SERR#最好不要乱动,其实这两个参数都不用动,因为你打开机箱就会失去质保,既然不安装PCI设备就不用动它。 看不懂惠普电脑BIOS怎么办?本文为大家提供惠普电

    2024年02月12日
    浏览(38)
  • 【简单入门】ChatGPT prompt engineering (中文版)笔记 |吴恩达ChatGPT 提示工程

    出处:https://download.csdn.net/download/weixin_45766780/87746321 感谢中文版翻译https://github.com/datawhalechina/prompt-engineering-for-developers/tree/main/content 国内 == 需要对openapi的endpoint做一个反向代理,并修改本地openai包的源代码== 如下图: completion 原则一:编写清晰、具体的指令 你应该通过提供

    2024年02月05日
    浏览(37)
  • 《深入理解Java虚拟机(第三版)》读书笔记:Java内存区域与内存溢出异常、垃圾收集器与内存分配策略

    下文是阅读《深入理解Java虚拟机(第3版)》这本书的读书笔记,如有侵权,请联系删除。 Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域。这些区域有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而一直存在,有

    2024年02月03日
    浏览(33)
  • 《Effective C++ 改善程序与设计的55个具体做法》读书笔记

    条款01 视C++为一个语言联邦 C Object-Oriented C++ Template C++ STL C++ 高效编程守则视情况而变化,取决于你使用 C++ 的哪一部分。 条款02 尽量与const,enum,inline替换#define 对于单纯常量,最好以 const 对象或 enums 替换 #defines 。 对于形似函数的宏( macros ),最好改用 inline 函数替换

    2024年02月12日
    浏览(26)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包