文章分类 -  Effective C++

摘要:“placement new” 通常是专指指定了位置的 new(std::size_t size, void mem),用于 vector 申请 capacity 剩余的可用内存。 但广义的 ”placement new” 指的是拥有额外参数的 operator new。 new 和 delete 阅读全文 »
posted @ 2020-02-29 12:06 刘-皇叔 阅读(136) 评论(0) 推荐(0) 编辑
摘要:new 和delete 必须遵循的惯例 operator new 需要无限循环地获取资源,如果没能获取则调用 ”new handler”,不存在 ”new handler” 时应该抛出异常。 operator new 应该处理 size == 0 的情况。 operator delete 应该兼容空 阅读全文 »
posted @ 2020-02-29 11:57 刘-皇叔 阅读(129) 评论(0) 推荐(0) 编辑
摘要:为什么需要自定义 operator new 或 operator delete 检测使用错误。new 得到的内存如果没有 delete 会导致内存泄露,而多次 delete 又会引发未定义行为。如果自定义 operator new 来保存动态内存的地址列表,在 delete 中判断内存是否完整,便可 阅读全文 »
posted @ 2020-02-29 11:36 刘-皇叔 阅读(181) 评论(0) 推荐(0) 编辑
摘要:new 申请内存失败时会抛出 异常,此前会调用一个由 std::set_new_handler() 指定的错误处理函数。 set_new_handler() “new handler” 函数通过 std::set_new_handler() 来设置,std::set_new_handler() 定义 阅读全文 »
posted @ 2020-02-27 20:39 刘-皇叔 阅读(96) 评论(1) 推荐(1) 编辑
摘要:模板元编程(Template Metaprogramming,TMP)就是利用模板来编写那些在编译时运行的C++程序。 模板元程序(Template Metaprogram)是由C++写成的,运行在编译器中的程序。当程序运行结束后,它的输出仍然会正常地编译。 C++并不是为模板元编程设计的,但自90 阅读全文 »
posted @ 2020-02-27 20:14 刘-皇叔 阅读(225) 评论(0) 推荐(0) 编辑
摘要:STL迭代器回顾 最简单的迭代器是输入迭代器(input iterator)和输出迭代器(output iterator), 它们只能向前移动,可以读取/写入它的当前位置,但只能读写一次。比如 ostream_iterator 就是一个输出迭代器。 比它们稍强的是前向迭代器(forward iter 阅读全文 »
posted @ 2020-02-27 20:02 刘-皇叔 阅读(108) 评论(0) 推荐(0) 编辑
摘要:如果所有参数都需要隐式类型转换,该函数应当声明为非成员函数。在类模板中,需要所有参数隐式转换的函数应当声明为友元并定义在类模板中。 模板化的 Rational 模板参数推导出错 看起来很完美但它是有问题的。比如我们有如下的调用: 为什么第二条会出错呢?因为编译器无法推导出合适的模板参数来实例化 。 阅读全文 »
posted @ 2020-02-27 19:32 刘-皇叔 阅读(110) 评论(0) 推荐(0) 编辑
摘要:提到智能指针可用来自动释放堆中的内存,STL中的迭代器也是一种智能指针,它甚至支持链表元素指针的 操作。 这些高级特性是普通指针所没有的。本文以智能指针为例,介绍成员函数模板的使用。 隐式类型转换 智能指针虽然比普通指针提供了更多有用的特性,但也存在一些问题,比如我们有一个类的层级: 普通指针可以做 阅读全文 »
posted @ 2020-02-27 12:53 刘-皇叔 阅读(151) 评论(0) 推荐(0) 编辑
摘要:模板是个好东西,你可以在实现类型安全的同时少写很多代码。但模板提供的是编译期的多态, 即使你的代码看起来非常简洁短小,生成的二进制文件也可能包含大量的冗余代码。 因为模板每次实例化都会生成一个完整的副本,所以其中与模板参数无关的部分会造成代码膨胀。 把模板中参数无关的代码重构到模板外便可以有效地控制 阅读全文 »
posted @ 2020-02-27 11:50 刘-皇叔 阅读(104) 评论(0) 推荐(0) 编辑
摘要:从面相对象 C++ 转移到模板 C++ 时,你会发现类继承在某些场合不在好使了。 比如父类模板中的名称对子类模板不是直接可见的,需要通过 this 前缀、using 或显式地特化模板父类来访问父类中的名称。 因为父类模板在实例化之前其中的名称是否存在确实是不确定的,而 C++ 偏向于早期发现问题(e 阅读全文 »
posted @ 2020-02-26 21:02 刘-皇叔 阅读(144) 评论(0) 推荐(0) 编辑
摘要:模板参数声明 上面 class 和 typename 的使用没有区别,然而 typename 和 class 对编译器而言却是不同的东西。 typename 可以用来帮编译器识别嵌套从属类型名称,基类列表和成员初始化列表除外。 声明一个类型 typename 的第一个作用在于声明一个类型。为什么类型 阅读全文 »
posted @ 2020-02-26 20:36 刘-皇叔 阅读(268) 评论(0) 推荐(0) 编辑
摘要:面向对象设计中的类考虑的是显式接口和运行时多态, 而模板编程中的模板考虑的是隐式接口和编译期多态。 对类而言,显式接口是由函数签名表征的,运行时多态由虚函数实现; 对模板而言,隐式接口是由表达式的合法性表征的,编译期多态由模板初始化和函数重载的解析实现。 显式接口和运行时多态 一个类的显式接口是由 阅读全文 »
posted @ 2020-02-26 20:14 刘-皇叔 阅读(141) 评论(0) 推荐(0) 编辑
摘要:多继承 多继承是 C++ 特有的概念,在是否应使用多继承的问题上始终争论不断。一派认为单继承是好的,所以多继承更好; 另一派认为多继承带来的麻烦更多,应该避免多继承。 多继承比单继承复杂,引入了歧义的问题,以及虚继承的必要性; 虚继承在大小、速度、初始化/赋值的复杂性上有不小的代价,当虚基类中没有数 阅读全文 »
posted @ 2020-02-26 19:48 刘-皇叔 阅读(118) 评论(0) 推荐(0) 编辑
摘要:private 继承 public 继承表示 "is a" 的关系,这是因为编译器会在需要的时候将子类对象隐式转换为父类对象。 然而 private 继承则不然: Person 可以 eat,但 Student 却不能 eat。这是 private 继承和 public 继承的不同之处: 编译器不会 阅读全文 »
posted @ 2020-02-26 19:24 刘-皇叔 阅读(147) 评论(0) 推荐(0) 编辑
摘要:一个类型包含另一个类型的对象时,我们这两个类型之间是组合关系。组合是比继承更加灵活的软件复用方法。对象组合也同样拥有它的语义: 就对象关系来讲,组合意味着一个对象拥有另一个对象,是 "has a" 的关系; 就实现方式来讲,组合意味着一个对象是通过另一个对象来实现的,是 "is implemente 阅读全文 »
posted @ 2020-02-26 17:45 刘-皇叔 阅读(113) 评论(0) 推荐(0) 编辑
摘要:静态绑定与动态绑定 静态绑定是在编译期决定的,又称早绑定;动态绑定是在运行时决定的,又称晚绑定。 举例来讲,Rect 和 Circle 都继承自 Shape,Shape 中有虚方法draw。那么: 在编译期是不知道应该调用哪个 draw 的,因为编译期看到的类型都是一样的: 。 在运行时可以通过虚函 阅读全文 »
posted @ 2020-02-26 17:30 刘-皇叔 阅读(267) 评论(0) 推荐(0) 编辑
摘要:不要重写继承来的非虚函数 Derived 继承自 Base。如果 Base有一个非虚函数 func,那么客户会倾向认为下面两种调用结果是一样的: 然而重写非虚函数 func 将会造成上述调用结果不一致: 因为 pb 类型是 ,pd 类型是 ,对于普通函数 func 的调用是静态绑定的(在编译期便决定 阅读全文 »
posted @ 2020-02-26 17:07 刘-皇叔 阅读(519) 评论(0) 推荐(0) 编辑
摘要:替代虚函数实现的几种方案 比如你在开发一个游戏,每个角色都有一个 healthValue() 方法。很显然你应该把它声明为虚函数,可以提供默认的实现,让子类去自定义它。 这个设计方式太显然了你都不会考虑其他的设计方法。但有时确实存在更好的,本节便来举几个替代的所涉及方法。 非虚接口范式(NVI id 阅读全文 »
posted @ 2020-02-26 16:58 刘-皇叔 阅读(433) 评论(0) 推荐(0) 编辑
摘要:继承时的函数接口传递 当你 public 继承一个类时,接口是一定会被继承的,你可以选择子类是否应当继承实现: 不继承实现,只继承方法接口:纯虚函数。 继承方法接口,以及默认的实现:虚函数。 继承方法接口,以及强制的实现:普通函数。 Rect 和 Ellipse 都继承自 Shape。 public 阅读全文 »
posted @ 2020-02-25 20:33 刘-皇叔 阅读(120) 评论(0) 推荐(0) 编辑
摘要:隐藏名称是作用域的问题。 在 C++ 中每一对 都会开启一个新的作用域,并嵌套在当前作用域中。 可以看到 double x 隐藏了 int x,因为C++的名称隐藏规则隐藏的是名称,和类型无关! 继承作用域 子类可以访问父类中的名称,是因为子类的作用域是嵌套在父类的作用域中的。 这一点也很符合直觉: 阅读全文 »
posted @ 2020-02-25 20:07 刘-皇叔 阅读(89) 评论(0) 推荐(0) 编辑

点击右上角即可分享
微信分享提示