上一页 1 2 3 4 5 6 7 8 ··· 27 下一页
摘要: 面向对象设计中的类考虑的是显式接口和运行时多态, 而模板编程中的模板考虑的是隐式接口和编译期多态。 对类而言,显式接口是由函数签名表征的,运行时多态由虚函数实现; 对模板而言,隐式接口是由表达式的合法性表征的,编译期多态由模板初始化和函数重载的解析实现。 显式接口和运行时多态 一个类的显式接口是由 阅读全文
posted @ 2020-02-26 20:14 刘-皇叔 阅读(132) 评论(0) 推荐(0) 编辑
摘要: 多继承 多继承是 C++ 特有的概念,在是否应使用多继承的问题上始终争论不断。一派认为单继承是好的,所以多继承更好; 另一派认为多继承带来的麻烦更多,应该避免多继承。 多继承比单继承复杂,引入了歧义的问题,以及虚继承的必要性; 虚继承在大小、速度、初始化/赋值的复杂性上有不小的代价,当虚基类中没有数 阅读全文
posted @ 2020-02-26 19:48 刘-皇叔 阅读(113) 评论(0) 推荐(0) 编辑
摘要: private 继承 public 继承表示 "is a" 的关系,这是因为编译器会在需要的时候将子类对象隐式转换为父类对象。 然而 private 继承则不然: Person 可以 eat,但 Student 却不能 eat。这是 private 继承和 public 继承的不同之处: 编译器不会 阅读全文
posted @ 2020-02-26 19:24 刘-皇叔 阅读(140) 评论(0) 推荐(0) 编辑
摘要: 一个类型包含另一个类型的对象时,我们这两个类型之间是组合关系。组合是比继承更加灵活的软件复用方法。对象组合也同样拥有它的语义: 就对象关系来讲,组合意味着一个对象拥有另一个对象,是 "has a" 的关系; 就实现方式来讲,组合意味着一个对象是通过另一个对象来实现的,是 "is implemente 阅读全文
posted @ 2020-02-26 17:45 刘-皇叔 阅读(111) 评论(0) 推荐(0) 编辑
摘要: 不要重写继承来的非虚函数 Derived 继承自 Base。如果 Base有一个非虚函数 func,那么客户会倾向认为下面两种调用结果是一样的: 然而重写非虚函数 func 将会造成上述调用结果不一致: 因为 pb 类型是 ,pd 类型是 ,对于普通函数 func 的调用是静态绑定的(在编译期便决定 阅读全文
posted @ 2020-02-26 17:07 刘-皇叔 阅读(512) 评论(0) 推荐(0) 编辑
摘要: 替代虚函数实现的几种方案 比如你在开发一个游戏,每个角色都有一个 healthValue() 方法。很显然你应该把它声明为虚函数,可以提供默认的实现,让子类去自定义它。 这个设计方式太显然了你都不会考虑其他的设计方法。但有时确实存在更好的,本节便来举几个替代的所涉及方法。 非虚接口范式(NVI id 阅读全文
posted @ 2020-02-26 16:58 刘-皇叔 阅读(419) 评论(0) 推荐(0) 编辑
摘要: 继承时的函数接口传递 当你 public 继承一个类时,接口是一定会被继承的,你可以选择子类是否应当继承实现: 不继承实现,只继承方法接口:纯虚函数。 继承方法接口,以及默认的实现:虚函数。 继承方法接口,以及强制的实现:普通函数。 Rect 和 Ellipse 都继承自 Shape。 public 阅读全文
posted @ 2020-02-25 20:33 刘-皇叔 阅读(118) 评论(0) 推荐(0) 编辑
摘要: 隐藏名称是作用域的问题。 在 C++ 中每一对 都会开启一个新的作用域,并嵌套在当前作用域中。 可以看到 double x 隐藏了 int x,因为C++的名称隐藏规则隐藏的是名称,和类型无关! 继承作用域 子类可以访问父类中的名称,是因为子类的作用域是嵌套在父类的作用域中的。 这一点也很符合直觉: 阅读全文
posted @ 2020-02-25 20:07 刘-皇叔 阅读(88) 评论(0) 推荐(0) 编辑
摘要: public 继承意味着 "is a" C++ 面向对象程序设计中,最重要的规则便是:public 继承应当是"is a"的关系。当 Derived public 继承自 Base时, 相当于你告诉编译器和所有看到你代码的人:Base 是 Derived 的抽象,Derived 就是一个 Base, 阅读全文
posted @ 2020-02-25 09:13 刘-皇叔 阅读(96) 评论(0) 推荐(0) 编辑
摘要: 避免编译依赖 为了保证 Person 能够被编译,需要包含依赖的头文件: 这样就建立了定义 Person 的文件和这些头文件之间的编译依赖关系。如果这些头文件中的一些发生了变化,或者这些头文件所依赖的文件发生了变化,包含 Person 类的文件和使用了 Person 的文件一样必须重新编译,这样的层 阅读全文
posted @ 2020-02-14 10:22 刘-皇叔 阅读(187) 评论(0) 推荐(0) 编辑
摘要: inline 函数 inline 函数的优缺点 内联函数的好处太多了: 它没有宏的那些缺点,而且不需要付出函数调用的代价。 同时也方便了编译器基于上下文的优化。 但 inline 函数也并非免费的午餐: 在有限内存的机器上,过分热衷于 inline 化会使得程序对于可用空间来说过于庞大。即使使用了虚 阅读全文
posted @ 2020-02-12 21:37 刘-皇叔 阅读(210) 评论(0) 推荐(0) 编辑
摘要: 异常安全 异常安全 是指当异常发生时: 不会泄漏资源, 也不会使系统处于不一致的状态。 通常有三个异常安全级别:基本保证、强烈保证、不抛异常保证: 基本保证 。抛出异常后,对象仍然处于合法(valid)的状态。但不确定处于哪个状态。 强烈保证 。如果抛出了异常,程序的状态没有发生任何改变。就像没调用 阅读全文
posted @ 2020-02-11 08:50 刘-皇叔 阅读(87) 评论(0) 推荐(0) 编辑
摘要: 不要返回对象私有成员的句柄 句柄(handle)可以理解为持有其它对象的方法,引用,指针,和迭代器都是句柄。 不要返回对象私有成员的句柄。这样可以增加类的封装性、使得 const 函数更加 const, 也避免了空引用的创建。 直接返回私有成员的指针会导致私有成员被完全暴露。例如: class Po 阅读全文
posted @ 2020-02-09 21:55 刘-皇叔 阅读(149) 评论(0) 推荐(0) 编辑
摘要: C++的类型检查只在编译时执行,运行时没有类型错误的概念。 理论上讲只要你的代码可以编译那么就运行时就不会有不安全的操作发生。 但 C++ 允许类型转换,也正是类型转换破坏了理论上的类型系统。 C++ 中的类型转换 旧风格的强制类型转换 C 风格的类型转换: 函数风格的类型转换: 以上两种形式之间没 阅读全文
posted @ 2020-02-09 20:43 刘-皇叔 阅读(97) 评论(0) 推荐(0) 编辑
摘要: 存在控制流转移的代码中,你可能会不经意间定义无用的变量。例如: 推迟构造函数的执行 当抛出异常时,encrypted 是无用的根本不需要构造它。所以更好的写法是推迟 encrypted 的构造: 推迟到有构造参数时 构造一个对象再给它赋值不如直接用一个值初始化它, 所以上述代码还有改进的余地:直接用 阅读全文
posted @ 2020-02-09 11:38 刘-皇叔 阅读(185) 评论(0) 推荐(0) 编辑
摘要: swap 函数最初由 STL 引入,已经成为异常安全编程的关键函数, 同时也是解决自赋值问题的通用机制。 std 中它的基本实现是很直观的: 可以看到,上述 swap 是通过赋值和拷贝构造实现的。所以 std::swap 并未提供异常安全, 但由于 swap 操作的重要性,我们应当为自定义的类实现异 阅读全文
posted @ 2020-02-08 21:23 刘-皇叔 阅读(154) 评论(0) 推荐(0) 编辑
摘要: 当类型转换应该用于所有参数时,声明为非成员函数 最好不要提供隐式的类型转化, 但这条规则也存在特例,比如当我们需要创建数字类型的类时。正如 double 和int 能够自由地隐式转换一样, 我们的数字类型也希望能够做到这样方便的接口。 当然这一节讨论的问题不是是否应当提供隐式转换,而是如果运算符的所 阅读全文
posted @ 2020-02-08 20:47 刘-皇叔 阅读(126) 评论(0) 推荐(0) 编辑
摘要: 在类的是实现中,常常会面临成员函数和非成员函数的选择。比如一个浏览器类: 此时你要实现一个 clearEverything() 有两种方式: 面向对象原则指出,数据和数据上的操作应当绑定在一起,那么前者更好。 这是对面向对象的误解,面向对象设计的精髓在于封装,数据应当被尽可能地封装。 相比于成员函数 阅读全文
posted @ 2020-02-08 18:10 刘-皇叔 阅读(138) 评论(0) 推荐(0) 编辑
摘要: 数据成员声明为私有可以提供一致的接口语法,提供细粒度的访问控制,易于维护类的不变式,同时可以让作者的实现更加灵活。而且我们会看到,protected 并不比 public 更加利于封装。 语法一致性 你肯定也遇到过这种困惑,是否应该加括号呢: 如果我们把所有数据都声明为私有,那么在调用语法上,统一用 阅读全文
posted @ 2020-02-08 17:38 刘-皇叔 阅读(115) 评论(0) 推荐(0) 编辑
摘要: 不要返回空的引用或指针 一个典型的场景如下: 注意 返回的是 Rational 实例, 时便会调用 , 返回值被拷贝后用来初始化 c。这个过程涉及到多个构造和析构过程: 函数调用结束前,返回值被拷贝,调用拷贝构造函数。 函数调用结束后,返回值被析构。 c 被初始化,调用拷贝构造函数。 c 被初始化后 阅读全文
posted @ 2020-02-08 17:23 刘-皇叔 阅读(106) 评论(0) 推荐(0) 编辑
上一页 1 2 3 4 5 6 7 8 ··· 27 下一页