罗剑锋的C++实战笔记
罗剑锋
奇虎360技术专家,Nginx/OpenResty开源项目贡献者
立即订阅
3817 人已学习
课程目录
已完结 30 讲
0/4登录后,你可以任选4讲全文学习。
课前导读 (2讲)
开篇词 | 把C++从“神坛”上拉下来,这次咱这么学
免费
课前准备 | 搭建实验环境
概论 (5讲)
01 | 重新认识C++:生命周期和编程范式
02 | 编码阶段能做什么:秀出好的code style
03 | 预处理阶段能做什么:宏定义和条件编译
04 | 编译阶段能做什么:属性和静态断言
05 | 面向对象编程:怎样才能写出一个“好”的类?
语言特性 (5讲)
06 | auto/decltype:为什么要有自动类型推导?
07 | const/volatile/mutable:常量/变量究竟是怎么回事?
08 | smart_ptr:智能指针到底“智能”在哪里?
09 | exception:怎样才能用好异常?
10 | lambda:函数式编程带来了什么?
标准库 (4讲)
11 | 一枝独秀的字符串:C++也能处理文本?
12 | 三分天下的容器:恰当选择,事半功倍
13 | 五花八门的算法:不要再手写for循环了
14 | 十面埋伏的并发:多线程真的很难吗?
技能进阶 (4讲)
15 | 序列化:简单通用的数据交换格式有哪些?
16 | 网络通信:我不想写原生Socket
17 | 脚本语言:搭建高性能的混合系统
18 | 性能分析:找出程序的瓶颈
总结篇 (5讲)
19 | 设计模式(上):C++与设计模式有啥关系?
20 | 设计模式(下):C++是怎么应用设计模式的?
21 | 知识串讲(上):带你开发一个书店应用
22 | 知识串讲(下):带你开发一个书店应用
期末测试 | 这些C++核心知识,你都掌握了吗?
结束语 (1讲)
结束语 | 路远,未有穷期
轻松话题 (4讲)
轻松话题(一) | 4本值得一读再读的经典好书
轻松话题(二) | 给你分享我的工作百宝箱
轻松话题(三) | 提高生活质量的App
轻松话题(四) | 真正高效的生活,是张弛有度
罗剑锋的C++实战笔记
15
15
1.0x
00:00/00:00
登录|注册

05 | 面向对象编程:怎样才能写出一个“好”的类?

罗剑锋 2020-05-16
你好,我是 Chrono。
如果按照前几节课的惯例,今天应该是讲运行阶段的。但是,运行阶段跟前面的编码、预处理和编译阶段不同,它是动态的、实时的,内外部环境非常复杂,CPU、内存、磁盘、信号、网络套接字……各种资源交织在一起,可谓千变万化(正如我在第 1 节课里所说,每一个阶段的差异都非常大)。
解决这个阶段面临的问题已经不是编程技术了,更多的是要依靠各种调试、分析、日志工具,比如 GDB、Valgrind、Systemtap 等。
所以,我觉得把这些运行阶段的工具、技巧放在课程前面不是太合适,咱们还是往后延一延,等把 C++ 的核心知识点都学完了,再来看它比较好。
那么,今天要和你聊哪些内容呢?
我想了想,还是讲讲“面向对象编程”(Object Oriented Programming)吧。毕竟,它是 C++ 诞生之初“安身立命”的看家本领,也是 C++ 的核心编程范式。
不管我们是否喜欢,“面向对象”早就已经成为了编程界的共识和主流。C++、Java、Python 等流行的语言,无一不支持面向对象编程,而像 Pascal、BASIC、PHP 那样早期面向过程的语言,在发展过程中也都增加了对它的支持,新出的 Go、Swift、Rust 就更不用说了。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《罗剑锋的C++实战笔记》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(49)

  • Jason
    老师讲的很实用,读完很有收获,赞。小贴士里面提到的5,耳目一新,确实很有道理,其他语言如Java、C#、Python的源码文件都是一种类型,只有咱们c++是头文件和实现文件。曾经有Java同事跟我闲聊,你们C++这个头文件啊,鸡肋,我楞了一下,思考了几秒钟,竟然没有反驳的理由。

    作者回复: 因为C++继承C,而C这么做是有历史原因的,当时的计算机性能弱内存小,头和实现分离才方便处理。

    现在的计算机性能大幅度提升,所以这种方式也就没有太多必要了,我建议尽量用hpp的方式,和其他语言保持一致。

    2020-05-16
    4
    9
  • lckfa李钊
    关于老师的思考题,我个人的想法是本节的知识点还不足以写一个好的类,文中编码准则和常用技巧里的介绍只是在编码层面给出了建议,但是缺少方法论。少用继承,多用组合,这个建议可以再扩展深入点,比如有的鸟不会飞的例子,其实可以将Fly从Bird类抽离出来,将Fly实现成一个独立的接口类,和Bird类进行组合。
    另外既然面向对象的核心是 抽象 和封装,封装可以不言自明,但是抽象是个啥,没有言明,抽象具体到编码里,其实还是需要虚基类和继承语法的。
    总而言之,本篇基本是术,而缺少道的深度,所以看罢全文,我还是写不出一个“好”的类。
    当然,缺少设计模式思维才是写好一个类最大的障碍,设计模式大部分都是要基于继承关系的,所以老师提到的少用继承,我想并不是说继承不好,而是别使用很多层次的继承,造成不必要的风险和维护难度吧。

    作者回复:
    1.我的理解,抽象就是“建模”,用类在代码里建立一个现实对象的映射。

    2.设计模式更强调对象组合,而不是继承,类模式很少。

    3.继承是一种“硬”代码复用,关系比较强,不如组合灵活,我建议少用。当然这还是要建立在对继承等特性有比较深刻认识的基础上。

    2020-05-16
    1
    9
  • 軟件賺硬幣
    罗老师,我看标准库和boost库很多继承都超过3层哦。比如iostream里面的,ios_base到ios,再到istream,再到iostream(同时继承ostream),再到fstream。用了三四层继承和虚继承(多重继承)

    作者回复: 现实中有很多深层次继承的例子,但不是说这就是好的,实际上iostream就被很多人批评过。

    2020-05-16
    1
    6
  • 嵇斌
    1. 面向对象的首要原则 SRP,单一职责原则。这一点特别赞同。另外就是慎用继承,尽量使用组合去实现。分享一个小故事,之前因为代码要写单元测试,使用到了Google Mock,一开始以为 只有虚类才没被Mock,导致很多完全没有必要使用virtual的类使用了virtual,直到有一天看了文档:https://github.com/google/googletest/blob/master/googlemock/docs/cook_book.md#mocking-non-virtual-methods-mockingnonvirtualmethods 恍然大悟。

    2. 类的设计最好遵循RAII,即在构造时完成资源的初始化。但是我觉可能Chrono可能会在后续内存管理的课程中讲这个。

    作者回复: 现在C++有很多工具,比如智能指针,可以在外部帮着管理资源,还有对象池模式,集中申请释放。

    所以RAII还是要看情况,当然,如果资源确实是与类强相关,那么就用RAII自己管理。

    2020-05-16
    5
  • Eglinux
    在 .h 中将类的定义和实现写在一起,这样不是默认所有成员函数都内联了吗?

    作者回复: 是的,但是否内联是由编译器决定的,通常只有小的函数才会内联,大的函数不会内联,因为反而成本高不划算。

    2020-05-16
    4
  • 被讨厌的勇气
    将声明与实现放在同一个.hpp文件中,会不会降低编译速度?仅include声明,和include声明和实现对编译速度有什么影响?

    作者回复: 我觉得在现在主流的cpu上,差异应该不大。可以看一下标准库,全是头文件,可见标准委员会对这个也是有信心的。

    如果还是不放心,可以做一下测试,但可能只有超大项目才能测试出差异来。

    2020-05-17
    1
    2
  • Simon
    类内别名:this_type,这个会用在什么时机?

    作者回复: 因为它就是类自己,所以可以在类作用域里完全等价替代,比如用在委托构造函数、内部子类型、模板类型再定义等。

    2020-06-29
    1
  • 甘俊
    老师您好,这一段有点没看明白,能举个例子体现explicit的作用么?

    因为 C++ 有隐式构造和隐式转型的规则,如果你的类里有单参数的构造函数,或者是转型操作符函数,为了防止意外的类型转换,保证安全,就要使用“explicit”将这些函数标记为“显式”。

    作者回复: 比如说,有个构造函数A(int x),那么,A a = 1,这里就会有一个隐式构造。大多数时候这个不是问题,但有的时候会导致意外的转换。

    使用explicit可以禁止隐式转换,防止意外错误,总是显式的构造,更加安全。

    2020-06-07
    1
  • 屈肖东
    在类型别名里,感觉都很鸡肋,正常的名称大家普遍更能够接受,非要起一个别名,反而可能会影响代码的可读性。而且c++11本来就支持使用auto,感觉起别名大多数时候都没什么意义

    作者回复: 在类里面定义自己的类型别名还是有很多好处的,让别名局部化,更有意义。

    而且在定义成员变量的时候,是不能用auto的,类型别名可以简化代码,减少重复提高可读性。

    可以参考一下课程里的代码,再和不用别名的形式对比一下。

    2020-06-06
    1
  • Raysuner
    本菜鸟表示老师讲的很好,但我还是没有什么具体的思路能写出好的类。老师的方法经过提炼总结,对经验丰富的人员应该比较有帮助,但我还比较缺乏经验,显得有些笼统,希望老师以后能谈谈到底怎么用这个术,什么情况下用这个术

    作者回复: 学习C++,还有任何编程语言,都要有适当的实践,不然就只是“花架子”。

    可以看一些开源项目,从中领会这些设计原则。

    2020-05-23
    1
  • MrTin
    另外想请教老师,想转行做C++的话,主要可以做哪些方面的事情呢?

    作者回复: 目前C++主要做系统编程,比较偏底层,不像做应用那么范围广。可以去招聘网站上看看,C++职位都有哪些,再决定是否转。

    2020-05-21
    1
  • robonix
    定义一个新的名字空间,把内部类都“提”到外面,降低原来类的耦合度和复杂度。老师,这句话没看懂,能加一个简单的代码示例吗?

    作者回复: 大概就是这样
    ~~~
    namespace xxx {

    class inner_class {...};
    class big_class {...};

    }
    ~~~

    2020-05-21
    1
    1
  • java2c++
    老师好,这一点我不太赞同“使用 using 或 typedef 可以为类型起别名,既能够简化代码,还能够适应将来的变化。” 类型别名看似简化代码,实际上增加了阅读代码的难度,最近看公司c++老系统里一个系统里同一个类搞出好几个别名,太影响阅读效率了

    作者回复: 这个要看怎么用了。

    我说的是在类内部定义别名,控制别名的作用域,如果在外部定义别名就是另外一回事了。

    2020-05-18
    1
    1
  • 课外小贴士的2应该怎么来定义结构体更好?

    作者回复: 直接用struct,和class一样。

    我的是意思是不要再用C的typedef方法来定义结构体的别名了,没有必要。

    2020-05-16
    2
    1
  • Confidant.
    我正在学习设计模式里面的思想,刚觉得virtul帮我们设计类省了很多事情,纯虚基类还是很有必要的,这样可以在二进制层面复用代码,把链接推迟到运行时期,避免了我们在修改代码的时候,牵一发而动全身

    作者回复: 用virtual就要用跟它相关的一大堆特性了,属于比较“纯”的面向对象。

    但在现代C++里,可以用泛型来达到类似的效果,而且性能更高。

    2020-05-16
    2
    1
  • 范闲
    1.cpp中的面向对象是建立在封装,继承和多态上。其中继承和动态多态强相关。很多情况下类的继承应该是is-a,has-a的算是类的组合。
    2. 好的类个人认为应该可以表意。从设计上需要考虑类的几个构造是否都需要,从继承上考虑是否有作为基类的可能。

    作者回复: 说的很好。

    2020-05-16
    1
  • 阿鼎
    我的体会,设计模式,是为了应对变化,大量使用继承,绕来绕去,不如直接把可能变化的地方,用funtion&bind来的直接。

    作者回复: 对,有的时候用function会比虚函数、抽象类更灵活,这就是对象组合,也是策略模式。

    2020-05-16
    3
    1
  • 中山浪子
    老师,委托构造的时候,对象obj初始化时候调用构造函数A,然后委托给构造函数B去初始化,这个过程会不会多产生一个obj的临时对象?

    作者回复: 当然不会了,这就相当于一个普通的函数调用,都是在这一个对象身上完成的,标准委员会不可能没有考虑过这点,你放心。

    2020-07-17
  • 谷鱼
    面向对象是一种思想,主要考虑抽象和封装,我认同。既然是一种思想,必然有很多规范来执行,才能形成稳定可用的编程代码。

    利用文中说到的一些方法,目前还在学习c++.不过在python php 这种脚本语言来说,构建好的对象的成本还是有点高,不仅仅是需要本身的限制,也是需要很多良好的规范,这些都是思维层次和良好的经验。面向对象,经常用到,但是真的做到完全的好用的,还需要更多的内容。

    作者回复: 是的,要用好面向对象不是一件容易的事情。

    Python、php的脚本语言特性,决定了代码编写会比较随意,要写完全的面向对象就比较累。而C++自身对面向对象就有所规范,所以写起来会容易一点。

    继续努力吧,可以再参考后面的设计模式两讲。

    2020-07-10
  • 海漩涡
    c++的这些特性很繁琐,感觉污染了这个语言

    作者回复: 我也有同感,但换个角度来看,太“纯粹”的语言也不是什么好事,C++一直追求的是工程上的实用,而不是学术上的纯粹。

    好在C++不会强迫我们做这做那,在里面挑出自己喜欢的就好了。

    2020-07-07
收起评论
49
返回
顶部