- 博客(37)
- 资源 (6)
- 收藏
- 关注
原创 读书笔记《Effective C++》条款39:明智而审慎地使用private继承
如果class之间的继承关系是private,编译器不会自动将一个derived class对象转换为一个base class对象。由private base class继承而来的所有成员,在derived class中都会变成private属性,纵使它们在base class中原本是protected或public属性。
2017-05-29 23:43:23 219
原创 读书笔记《Effective C++》条款38:通过复合塑模出has-a或“根据某物实现出”
复合(composition)是类型之间的一种关系,当某种类型的对象内含它种类型的对象,便是这种关系。例如:class Addresss {};class PhoneNumber {};class Person {public: //...private: std::string name;//合成成分物(composed object) Address address;//同上
2017-05-28 19:19:12 395
原创 读书笔记《Effective C++》条款36:绝不重新定义继承而来的non-virtual函数
条款32说过,所谓public继承意味is-a(是一种)的关系。条款34则描述为什么在class内声明一个non-virtual函数会为该class建立一个不变性,凌驾其特异性。如果将这两个观点施行于两个class Base和Derived以及non-virtual成员函数Base::mf身上,那么:1.适用于Base对象的每一件事,也适用于Derived对象,因为每个Derived对象都是一
2017-05-26 23:44:24 199
原创 读书笔记《Effective C++》条款35:考虑virtual函数以外的其他选择
要点:1.virtual函数的替代方案包括NVI手法及Strategy设计模式的多种形式。NVI手法自身是一个特殊形式的Template Method设计模式。2.将机能从成员函数移到class外部函数,带来的一个缺点是,非成员函数无法访问class的non-public成员。
2017-05-26 00:15:20 223
原创 读书笔记《Effective C++》条款34:区分接口继承和实现继承
成员函数的接口总是会被继承。如条款32所说,public继承意味is-a,所以对base class为真的任何事情一定也对其derived class为真。因此如果某个函数可施行于某class身上,一定也可施行于其derived class身上。声明一个pure virtual函数的目的是为了让derived class只继承函数接口。声明impure virtual函数的目的,是让der
2017-05-25 23:35:41 186
原创 读书笔记《Effective C++》条款33:避免遮掩继承而来的名称
我们知道在诸如这般的代码中:int x;//global变量void someFunc(){ double x;//local变量 std::cin >> x;//读一个新值赋予local变量x}这个读取数据的语句指涉的是local变量x,而不是global变量x,因为内层作用域的名称会遮掩外围作用域的名称。当编译器处于someFunc的作用域内并遭遇
2017-05-24 23:50:36 275
原创 读书笔记《Effective C++》条款32:确定你的public继承塑模出is-a关系
以C++进行面向对象编程,最重要的一个规则是:public inheritance(公开继承)意味“is-a”(是一种)的关系。如果你令class D(“Derived”)以public形式继承class B(“Base”),你便是告诉C++编译器,每一个类型为D的对象同时也是一个类型为B的对象,反之不成立。也就是说,B比D表现出更一般化的概念,而D比B表现出更特殊化的概念。B对象可派上用场的
2017-05-24 23:12:10 271
原创 读书笔记《Effective C++》条款31:将文件间的编译依存关系降至最低
要点:1.支持“编译依存性最小化”的一般构想是:相依于声明式,不要相依于定义式。基于此构想的两个手段是Handle classes和Interface classes。2.程序库头文件应该以“完全且仅有声明式”的形式存在。这种做法不论是否涉及template都适用。
2017-05-21 23:24:50 227
原创 读书笔记《Effective C++》条款30:透彻了解inlining的里里外外
inline函数,可以调用它们又不需要函数调用所招致的额外开销。inline函数背后的整体观念是,将“对此函数的每一个调用”都以函数本体替换之。这样做可能增加目标码大小,引发代码膨胀。换个角度说,如果inline函数的本体很小,编译器对“函数本体”所产出的码可能比针对“函数调用”所产出的码更小。inline可以以隐喻方式将函数定义于class定义式内,任何在类内部定义的函数自动地成为inl
2017-05-21 21:31:18 215
原创 读书笔记《Effective C++》条款29:为“异常安全”而努力是值得的
异常安全函数提供以下三个保证之一:1.基本承诺:如果异常被抛出,程序内的任何事物仍然保持在有效状态下。没有任何对象或数据结构会因此而败坏,所有对象都处于一种内部前后一致的状态。2.强烈保证:如果异常被抛出,程序状态不改变。调用这样的函数需有这样的认知:如果函数成功,就是完全成功;如果函数失败,程序会回复到“调用函数之前”的状态。3.不抛掷(nothrow)保证:承诺绝不抛出异常,因为它
2017-05-21 21:04:11 289
原创 C++构造函数初始化列表中不能使用this指针
先看个例子:class Point {//这个class用来表述“点”public: Point(int x, int y) : this->x(x), this->y(y) { } void setX(int x) { this->x = x; } void setY(int y) { this->y = y; }public: int x; int y;}
2017-05-21 15:36:05 8305
原创 读书笔记《Effective C++》条款27:尽量少做转型动作
C语言风格的转型动作有两种形式:(T)expression //将expression转型为TT(expression) //将expression转型为T两种形式并不差别。C++还提供四种新式转型:const_cast(expression)dynamic_cast(expression)reinterpret_cast(expression)st
2017-05-20 22:20:30 285
原创 读书笔记《Effective C++》条款26:尽可能延后变量定义式的出现时间
只要定义了一个变量而其类型带有一个构造函数或析构函数,那么当code flow到达这个变量定义式时,便得承受构造成本;当这个变量离开作用域时,便得承受析构成本。即使这个变量始终并未被使用,仍需耗费这些成本,所以应该尽可能避免这种情形。或许会认为,不可能定义一个不使用的变量,但是比如下使用变量前,有一个异常被抛出,那这个变量就真的没有被使用,同时还得付出构造成本和析构成本。所以最好延后定义,直到
2017-05-20 11:13:29 196
原创 读书笔记《Effective C++》条款25:考虑写出一个不抛异常的swap函数
所谓swap(置换)两对象值,意思是将两对象的值彼此赋予对方。缺省情况下swap动作可有标准程序库提供的swap算法完成。namespace std { template void swap(T& a, T& b) { T temp(a); a = b; b = temp; }}只要类型T支持copying(copy构造函数和copy assignment操作符),缺
2017-05-20 09:42:23 219
原创 读书笔记《Effective C++》条款23:宁以non-member、non-friend替换member函数
先看个例子,想象有个class用来表示网页浏览器。这样的class可能提供的众多函数中,有一些用来清楚下载元素告诉缓存区、清楚访问过的URLs的历史记录、以及移除系统中的所有cookies:class WebBrowser {public: void clearCache(); void clearHistory(); void removeC
2017-05-16 23:44:15 221
原创 读书笔记《Effective C++》条款22:将成员变量声明为private
要点:1.切记将成员变量声明为private。2.protected并不比public更具封装性。
2017-05-16 00:13:31 200
原创 读书笔记《Effective C++》条款21:必须返回对象时,别妄想返回其reference
任何函数如果返回一个reference和指针指向某个local对象,都将出问题,因为local对象在函数结束时就被销毁了。const Rational& operator* (const Rational& lhs, const Rational& rhs){ Rational result(lhs.n * rhs.n, lhs.d * rhs.d);//糟糕的代码
2017-05-15 23:48:47 252
原创 读书笔记《Effective C++》条款20:宁以pass-by-reference-to-const替换pass-by-value
缺省情况下C++以by value方式传递对象至(或来自)函数。如果你另外指定,否则函数参数都是以实际参数的复件为初值,而调用端所获得的亦是函数返回值的一个复件。这些复件(副本)系由对象的copy构造函数产出,这可能使得pass-by-value成为昂贵的(费时的)操作。
2017-05-14 23:56:45 213
原创 读书笔记《Effective C++》条款19:设计class犹如设计type
C++就像在其他OOP(面向对象编程)语言一样,当你定义一个新class,也就定义了一个新type。应该带着和“语言设计者当初设计语言内置类型时”一样的谨慎来研讨class的设计。设计优秀的class是一项艰巨的工作,因为设计好的types是一项艰巨的工作。好的types有自然的语法,直观的语义,以及一或多个高效实现品。在C++中,一个不良规划下的class定义恐怕无法达到上述任何一个目标。甚
2017-05-14 23:12:23 191
原创 读书笔记《Effective C++》条款18:让接口容易被正确使用,不易被误用
function接口,class接口,template接口......每一种接口都是客户与代码互动的手动。
2017-05-13 13:01:36 192
原创 读书笔记《Effective C++》条款17:以独立语句将newed对象置入智能指针
假设我们有两个函数用来揭示处理程序的优先权,另一个函数用来在某动态分配所得的Widget上进行某些带有优先权的处理:int priority();void processWidget(std::shared_ptr pw, int priority);由于谨记“以对象管理资源”(条款13),processWidget决定对其动态分配得来的Widget运用智能指针。现在考虑调用proc
2017-05-13 12:11:47 263
原创 读书笔记《Effective C++》条款16:成对使用new和delete时要采取相同形式
以下程序会有什么错?std::string* stringArray = new std::string[100];...delete stringArray;看上去都井然有序,使用了new,也搭配使用了对应的delete,但还是有个某个完全错误:程序行为不明确。最低限度,stringArray所含的100个string对象中的99个不太可能被适当删除,因为它们的析构函数很可能没有被调
2017-05-12 22:43:28 212
原创 读书笔记《Effective C++》条款15:在资源管理类中提供对原始资源的访问
资源管理类很棒。它们是我们对抗资源泄露的堡垒。排除此等泄露是良好设计系统的根本性质。但事实是,许多APIs直接指涉资源,所以除非你发誓永不录用这样的APIs,否则只得绕过资源管理器对象(resource-managing objects)直接访问原始资源(raw resource)。看例子:
2017-05-12 00:01:24 276
原创 读书笔记《Effective C++》条款14:在资源管理类中小心copying行为
条款13导入这样的观念:“资源取得时机便是初始化时机(RAII)”,并以此作为“资源管理类”的脊柱,也描述了auto_ptr和shared_ptr如何将这个观念表现在heap-based资源上。然而并非所有资源都是heap-based,对那种资源而言,像auto_ptr和shared_ptr这样的智能指针往往不适合作为资源管理者。既然如此,有时,需要我们建立自己的资源管理类。例如,假设使用C
2017-05-08 23:46:10 320
原创 读书笔记《Effective C++》条款12:复制对象时勿忘其每一个成分
“编译器生成版”的copy构造函数和copy assignment操作符行为:将被拷对象的所有成员变量都做一份copy。如果你声明自己的copying函数,意思就是告诉编译器不喜欢缺省实现中的某些行为。编译器仿佛被冒犯似的,会以一种奇怪的方式回敬:当你的实现代码几乎必然出错时却不告诉你。直接看例子:
2017-05-07 10:04:58 174
原创 读书笔记《Effective C++》条款10:令operator=返回一个reference to *this
关于赋值,有趣的是你可以把它们写成连锁形式:int x, y, z;x = y = z = 15;//赋值连锁形式同样有趣的是,赋值采用右结合率,所以上述连锁赋值被解析为:x = (y = (z = 15));为了实现”连锁赋值“,赋值操作符必须返回一个reference指向操作符的左侧实参。class Widget{public: Widget& operator=(c
2017-05-06 17:50:47 430
原创 读书笔记《Effective C++》条款09:绝不在构造和析构过程中调用virtual函数
先看一个例子:class Transaction {//所有交易的abstract base classpublic: Transaction(); virtual void logTransaction() const = 0;//做出一份因类型不同而不同的日志记录(log entry)};class BuyTransaction : public Transaction {//
2017-05-06 16:48:04 222
原创 读书笔记《Effective C++》条款08:别让异常逃离析构函数
C++并不禁止析构函数吐出异常,但它不鼓励这样做。这是有理由的。考虑以下代码:当vector v被销毁,它有责任销毁其内含的所有Widgets。
2017-05-06 13:32:10 249
原创 读书笔记《Effective C++》条款07:为多态基类声明virtual析构函数
开篇例子,有许多种做法可以记录时间,因此,设计一个TimeKeeper base class和一些derived classes作为不同的计时方法。class TimeKeeper {public: TimeKeeper() { std::cout << "TimeKeeper constructor" << std::endl; } ~TimeKeeper() { std::
2017-05-06 10:11:13 240
原创 读书笔记《Effective C++》条款06:若不想使用编译器自动生成的函数,就该明确拒绝
所有编译器产出的函数都是public。如果不想让编译器自动生成这些函数,得自行声明它们,可以将copy构造函数或copy assignment操作符声明为private,这样就阻止了编译器暗自创建的版本,而且令这些函数为private,得以成功阻止人们调用它们。一般而言这个做法并不绝对安全,因为member函数和friend函数还是可以调用private函数。有种办法:只声明这些private
2017-05-04 00:22:44 384
原创 读书笔记《Effective C++》条款05:了解C++默默编写并调用哪些函数
对于一个空类(如果自己没声明),编译器就会为它声明(编译器版本的)一个default构造函数、一个copy构造函数、一个copy assignment操作符和一个析构函数。所有这些函数都是public且inline。如果没有声明任何构造函数,编译器会为你声明一个default构造函数,如果已有构造函数,编译器就不会在为你声明一个default构造函数。
2017-05-01 23:25:28 207
原创 读书笔记《Effective C++》条款04:确定对象被使用前已先被初始化
读取未初始化的值会导致不明确的行为。在C语言中,全局变量和static变量一般会有初始化值,而对于局部变量没有定义初始化值。在C++中,有了class后,情况就更加复杂了。对于何时有初始化值,何时没有,记忆起来很复杂。最佳处理办法:永远在使用对象之前先将它初始化。对于无任何成员的内置类型,必须手动完成。至于内置类型以外的任何其他东西,初始化责任落在构造函数(constructors)身上。规则
2017-05-01 12:10:53 246
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人