现代C++实战30讲
吴咏炜
前 Intel 资深软件架构师
立即订阅
3745 人已学习
课程目录
已更新 18 讲 / 共 30 讲
0/4登录后,你可以任选4讲全文学习。
课前必读 (2讲)
开篇词 | C++这么难,为什么我们还要用C++?
免费
课前必读 | 有关术语发音及环境要求
基础篇 (9讲)
01 | 堆、栈、RAII:C++里该如何管理资源?
02 | 自己动手,实现C++的智能指针
03 | 右值和移动究竟解决了什么问题?
04 | 容器汇编 I:比较简单的若干容器
05 | 容器汇编 II:需要函数对象的容器
06 | 异常:用还是不用,这是个问题
07 | 迭代器和好用的新for循环
08 | 易用性改进 I:自动类型推断和初始化
09 | 易用性改进 II:字面量、静态断言和成员函数说明符
提高篇 (7讲)
10 | 到底应不应该返回对象?
11 | Unicode:进入多文字支持的世界
12 | 编译期多态:泛型编程和模板入门
13 | 编译期能做些什么?一个完整的计算世界
14 | SFINAE:不是错误的替换失败是怎么回事?
15 | constexpr:一个常态的世界
16 | 函数对象和lambda:进入函数式编程
现代C++实战30讲
登录|注册

12 | 编译期多态:泛型编程和模板入门

吴咏炜 2019-12-23
你好,我是吴咏炜。
相信你对多态这个面向对象的特性应该是很熟悉了。我们今天来讲一个非常 C++ 的话题,编译期多态及其相关的 C++ 概念。

面向对象和多态

在面向对象的开发里,最基本的一个特性就是“多态” [1]——用相同的代码得到不同结果。以我们在 [第 1 讲] 提到过的 shape 类为例,它可能会定义一些通用的功能,然后在子类里进行实现或覆盖:
class shape {
public:
void draw(const position&) = 0;
};
上面的类定义意味着所有的子类必须实现 draw 函数,所以可以认为 shape 是定义了一个接口(按 Java 的概念)。在面向对象的设计里,接口抽象了一些基本的行为,实现类里则去具体实现这些功能。当我们有着接口类的指针或引用时,我们实际可以唤起具体的实现类里的逻辑。比如,在一个绘图程序里,我们可以在用户选择一种形状时,把形状赋给一个 shape 的(智能)指针,在用户点击绘图区域时,执行 draw 操作。根据指针指向的形状不同,实际绘制出的可能是圆,可能是三角形,也可能是其他形状。
但这种面向对象的方式,并不是唯一一种实现多态的方式。在很多动态类型语言里,有所谓的“鸭子”类型 [2]
如果一只鸟走起来像鸭子、游起泳来像鸭子、叫起来也像鸭子,那么这只鸟就可以被当作鸭子。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《现代C++实战30讲》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(6)

  • Geek_077da0
    老师您好,看到这一讲想问一个一直想问的问题。我是一个在校学生,目前学完了c++的基本语法知识并且看了一些相关的书籍,但平时能自己动手写代码的机会只有刷leetcode的时候,想请问一下老师,在去公司实习之前,有没有什么项目适合初学者练练手的。不然感觉自己看了这么多理论终究只是在纸上谈兵。

    作者回复: 可以尝试把平时用 Python、Bash 写的小工具改成用 C++。使用现代 C++,这种处理也不会太麻烦。

    还有就是小的网络应用、数据处理应用等等。Leetcode 是考算法的,对语言技巧是没啥帮助。

    2019-12-23
    2
  • 花晨少年
    参数满足随机访问迭代器的要求。
    ———
    是因为sort 是个复合排序,主体是使用 快速排序,而快排貌似是有随机访问的需求吗

    作者回复: sort不一定是快速排序,但通用的高性能排序算法一般都要求随机访问。sort解决的是通用情况。list::sort 则解决一种不能随机访问的特殊情况。

    2019-12-29
  • lyfei
    老师您好,就是我对容器共性这一块有点疑惑:
    比如老师讲的容器中的共性:begin, end等,但是又提到" C++ 的标准容器没有对象继承关系";那对于不同的容器来说,vector, map, list等都得各自去实现自己的begin, end方法吗?
    那既然不同的容器有着诸多的共性,为什么C++里不用继承呢?
    谢谢老师的回复

    作者回复: 想一想:

    为什么要继承?继承的话,能带来什么好处?

    2019-12-24
    1
  • Scott
    请问前几讲中最后的问题的答案可以公布一下吗?

    作者回复: 具体一点吧。哪一题你特别想知道又没有正确的回答?😎

    2019-12-24
  • 总统老唐
    吴老师,学完这一课,有 3 点疑问:
    1,你提到的方法一,“添加代码,让那个类型支持所需要的操作(对成员函数无效)”,这里说“对成员函数无效”是具体指的什么情况?
    2,实现static_assert功能时,定义 struct 模板如下: template<bool> struct compile_time_error, 和常见的模板定义头部 template <typename T> 的格式看起来不一样,常见的这种格式中参数类型是未定的,但是compile_time_error这个模板,参数明确指定是 bool 型,这是模板的另一种形式么?
    3,我尝试做了以下实验
    template <typename T>
    T addData(T a, T b)
    {
        return a + b;
    }

    double addData(double a, double b)
    {
        return (int)a + (int)b;
    }

    template <>
    double addData(double a, double b)
    {
        return (int)a + (int)b;
    }
    当我调用 addData(1.5, 2.5)时,发现调用的是针对double的重载函数,而不是模板针对double 的特化,这是为什么?

    作者回复: 1. 一般而言,不应该去修改别人的类。容易出问题。所以不能添加成员函数。

    2. 模板参数可以是类型,也可以是常数表达式,包括整数类型常数、枚举、指针、引用。

    3. 重载比特化优先。一般而言,函数特化是不推荐的。具体看参考资料 3。

    2019-12-24
  • tt
    从来没有把C++的模板编程和鸭子类型联系到一起,以前一提到鸭子类型,就想到了PYTHON和JAVASCRIPT。现在想想,按照鸭子类型的定义,那么JAVA也是支持它的。

    一直感觉C++的模板编程就是一个静态实现的“动态类型子语言”:完全可以像写JAVASCRIPT一样写C++代码,只是需要先编译一下再运行。也许JAVASCRIPT的实现比如V8引擎应该大量使用它吧。

    但最后的总结,静态多态主要是用于算法复用。好像上面的想法又不太行的通了。不过,如果把类型的行为也看作一种算法的话,似乎又是一个解决办法。

    没看过V8这么复杂的源码,也许有一天去看看吧。

    作者回复: 静态语言的鸭子类型和动态语言还是有区别的。毕竟静态语言,如 C++,需要在编译时绑定所有的符号,否则就会出错……下面还会有例子,和 C++ 如何试图解决、改善这些问题的。编译期行为要讲上很多讲的。

    2019-12-23
收起评论
6
返回
顶部