C++
文章平均质量分 69
Do-Program
这个作者很懒,什么都没留下…
展开
-
C++ 对象内存布局和多态实现原理
进入主题前,先把工具设置好。本文使用编译测试环境:Visual Studio 2013VS2013查看类内存布局设置方式如下截图:先选择左侧的C/C++->命令行,然后在其他选项这里写上/d1 reportAllClassLayout,它可以看到所有相关类的内存布局,如果写上/d1 reportSingleClassLayoutXXX(XXX为类名),则只会打出指定类XXX原创 2017-08-23 17:57:27 · 1097 阅读 · 1 评论 -
读书笔记《Effective C++》条款37:绝不重新定义继承而来的缺省参数值
virtual函数系动态绑定,而缺省参数值却是静态绑定。原创 2017-05-28 16:26:05 · 268 阅读 · 0 评论 -
读书笔记《Effective C++》条款35:考虑virtual函数以外的其他选择
要点:1.virtual函数的替代方案包括NVI手法及Strategy设计模式的多种形式。NVI手法自身是一个特殊形式的Template Method设计模式。2.将机能从成员函数移到class外部函数,带来的一个缺点是,非成员函数无法访问class的non-public成员。原创 2017-05-26 00:15:20 · 216 阅读 · 0 评论 -
读书笔记《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 · 196 阅读 · 0 评论 -
读书笔记《Effective C++》条款24:若所有参数皆需类型转换,请为此采用non-member函数
要点:原创 2017-05-17 23:15:22 · 352 阅读 · 0 评论 -
读书笔记《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 · 209 阅读 · 0 评论 -
读书笔记《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 · 183 阅读 · 0 评论 -
读书笔记《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 · 267 阅读 · 0 评论 -
读书笔记《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 · 258 阅读 · 0 评论 -
读书笔记《Effective C++》条款31:将文件间的编译依存关系降至最低
要点:1.支持“编译依存性最小化”的一般构想是:相依于声明式,不要相依于定义式。基于此构想的两个手段是Handle classes和Interface classes。2.程序库头文件应该以“完全且仅有声明式”的形式存在。这种做法不论是否涉及template都适用。原创 2017-05-21 23:24:50 · 215 阅读 · 0 评论 -
读书笔记《Effective C++》条款30:透彻了解inlining的里里外外
inline函数,可以调用它们又不需要函数调用所招致的额外开销。inline函数背后的整体观念是,将“对此函数的每一个调用”都以函数本体替换之。这样做可能增加目标码大小,引发代码膨胀。换个角度说,如果inline函数的本体很小,编译器对“函数本体”所产出的码可能比针对“函数调用”所产出的码更小。inline可以以隐喻方式将函数定义于class定义式内,任何在类内部定义的函数自动地成为inl原创 2017-05-21 21:31:18 · 209 阅读 · 0 评论 -
读书笔记《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 · 335 阅读 · 0 评论 -
读书笔记《Effective C++》条款40:明智而审慎地使用多重继承
要点:1.多重继承比单一继承复杂。它可能导致新的歧义性,以及对virtual继承的需要。2.virtual继承会增加大小、速度、初始化(及赋值)复杂度等等成本。如果virtual base class不带任何数组,将是最具实用价值的情况。3.多重继承的确有正当用途。其中一个情节涉及“public继承某个interface class”和“private继承某个协助实现的class”的两相组合。原创 2017-06-01 23:41:18 · 251 阅读 · 0 评论 -
读书笔记《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 · 210 阅读 · 0 评论 -
读书笔记《Inside the C++ Object Model》:关于对象
在C++中,有两种class data members:static和nonstatic,以及三种class member functions:static,nonstatic和virtual。C++对象模型(The C++ Object Model)Nonstatic data members被配置于每一个class object之内,static data members则被存放在个别原创 2017-08-19 10:52:04 · 247 阅读 · 0 评论 -
读书笔记《Inside the C++ Object Model》:Default Constructor的构造操作
C++新手一般有两个常见的误解:1.任何class如果没有定义default constructor,就会被合成出一个来。2.编译器合成出来的default constructor会显示设定“class内的每一个data member的默认值”。实际上,没有一个是真的!C++ Annotated Reference Manual(ARM)告诉我们“default const原创 2017-08-19 13:53:18 · 245 阅读 · 0 评论 -
读书笔记《Inside the C++ Object Model》:Copy Constructor的构造操作
有三种情况,会以一个object的内容作为另一个class object的初值。最明显的一种情况当然就是对一个object做显示的初始化操作,另两种情况是当object被当做参数交给某个函数时,以及当函数传回一个class object时。如果class没有提供一个explicit copy constructor又当如何?当class object以“相同class的另一个object”原创 2017-08-20 11:57:13 · 201 阅读 · 0 评论 -
读书笔记《Effective C++》条款41:了解隐式接口和编译器多态
面向对象编程总是以显示接口(在源码中明确可见)和运行期多态解决问题。Template及泛型编程,与面向对象有根本的不同。在此世界中显示接口和运行期多态仍然存在,但重要性降低。反倒是隐式接口和编译器多态移到前头了。templatevoid doProcessing(T& w){ if (w.size() > 10 && w != someNastyWidget) {原创 2017-06-03 15:09:59 · 263 阅读 · 0 评论 -
读书笔记《Effective C++》条款42:了解typename的双重意义
以下template声明中,class和typename有什么不同?template class Widget;//使用classtemplate class Widget;//使用typename答案:没有不同。当我们声明template类型参数,class和typename的意义完全相同。然而,C++并不总是把class和typename视为等价。有时候一定得使用typename原创 2017-06-03 22:49:37 · 300 阅读 · 0 评论 -
读书笔记《Effective C++》条款43:学习处理模板化基类内的名称
要点:可在derived class template内通过“this->”指涉base class template内的成员名称,或藉由一个明白写出的“base class资格修饰符”完成。原创 2017-06-17 21:07:13 · 266 阅读 · 0 评论 -
读书笔记《Effective C++》条款44:将与参数无关的代码抽离template
Template是节省时间和避免代码重复的一个奇方妙法。不再需要键入20个类似的class而每一个带有15个成员函数,你只需要键入一个class template,留个编译器去具现化那20个你需要的相关class和300个函数。(class template的成员函数只有在被使用时才被暗中具现化,所以只有在这300个函数的每一个被使用,你才会获得这300个函数)Function template有原创 2017-06-17 22:50:33 · 245 阅读 · 0 评论 -
读书笔记《Effective C++》条款26:尽可能延后变量定义式的出现时间
只要定义了一个变量而其类型带有一个构造函数或析构函数,那么当code flow到达这个变量定义式时,便得承受构造成本;当这个变量离开作用域时,便得承受析构成本。即使这个变量始终并未被使用,仍需耗费这些成本,所以应该尽可能避免这种情形。或许会认为,不可能定义一个不使用的变量,但是比如下使用变量前,有一个异常被抛出,那这个变量就真的没有被使用,同时还得付出构造成本和析构成本。所以最好延后定义,直到原创 2017-05-20 11:13:29 · 189 阅读 · 0 评论 -
读书笔记《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 · 218 阅读 · 0 评论 -
读书笔记《Effective C++》条款29:为“异常安全”而努力是值得的
异常安全函数提供以下三个保证之一:1.基本承诺:如果异常被抛出,程序内的任何事物仍然保持在有效状态下。没有任何对象或数据结构会因此而败坏,所有对象都处于一种内部前后一致的状态。2.强烈保证:如果异常被抛出,程序状态不改变。调用这样的函数需有这样的认知:如果函数成功,就是完全成功;如果函数失败,程序会回复到“调用函数之前”的状态。3.不抛掷(nothrow)保证:承诺绝不抛出异常,因为它原创 2017-05-21 21:04:11 · 277 阅读 · 0 评论 -
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 · 8264 阅读 · 0 评论 -
读书笔记《Effective C++》条款04:确定对象被使用前已先被初始化
读取未初始化的值会导致不明确的行为。在C语言中,全局变量和static变量一般会有初始化值,而对于局部变量没有定义初始化值。在C++中,有了class后,情况就更加复杂了。对于何时有初始化值,何时没有,记忆起来很复杂。最佳处理办法:永远在使用对象之前先将它初始化。对于无任何成员的内置类型,必须手动完成。至于内置类型以外的任何其他东西,初始化责任落在构造函数(constructors)身上。规则原创 2017-05-01 12:10:53 · 240 阅读 · 0 评论 -
读书笔记《Effective C++》条款05:了解C++默默编写并调用哪些函数
对于一个空类(如果自己没声明),编译器就会为它声明(编译器版本的)一个default构造函数、一个copy构造函数、一个copy assignment操作符和一个析构函数。所有这些函数都是public且inline。如果没有声明任何构造函数,编译器会为你声明一个default构造函数,如果已有构造函数,编译器就不会在为你声明一个default构造函数。原创 2017-05-01 23:25:28 · 189 阅读 · 0 评论 -
读书笔记《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 · 213 阅读 · 0 评论 -
读书笔记《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 · 421 阅读 · 0 评论 -
读书笔记《Effective C++》条款11:令operator=中处理”自我赋值“
”自我赋值“发生在对象被赋值给自己时原创 2017-05-06 18:08:34 · 230 阅读 · 0 评论 -
读书笔记《Effective C++》条款12:复制对象时勿忘其每一个成分
“编译器生成版”的copy构造函数和copy assignment操作符行为:将被拷对象的所有成员变量都做一份copy。如果你声明自己的copying函数,意思就是告诉编译器不喜欢缺省实现中的某些行为。编译器仿佛被冒犯似的,会以一种奇怪的方式回敬:当你的实现代码几乎必然出错时却不告诉你。直接看例子:原创 2017-05-07 10:04:58 · 166 阅读 · 0 评论 -
读书笔记《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 · 280 阅读 · 0 评论 -
读书笔记《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 · 206 阅读 · 0 评论 -
读书笔记《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 · 306 阅读 · 0 评论 -
读书笔记《Effective C++》条款15:在资源管理类中提供对原始资源的访问
资源管理类很棒。它们是我们对抗资源泄露的堡垒。排除此等泄露是良好设计系统的根本性质。但事实是,许多APIs直接指涉资源,所以除非你发誓永不录用这样的APIs,否则只得绕过资源管理器对象(resource-managing objects)直接访问原始资源(raw resource)。看例子:原创 2017-05-12 00:01:24 · 265 阅读 · 0 评论 -
读书笔记《Effective C++》条款03:尽可能使用const
const允许你指定一个语义约束(也就是指定一个“不该被改动”的对象),而编译器会强制实施这项约束。它允许你告诉编译器和其他程序员某值应该保持不变。可以用const在class外部修饰global或namespace作用域中的常量,或修饰文件、函数、或区块作用域(block scope)中被声明为static的对象。也可以用它修饰class内部的static和non-static成员变量。原创 2017-04-25 23:54:19 · 241 阅读 · 0 评论 -
读书笔记《Effective C++》条款02:尽量以const,enum,inline替换#define
#define是由预编译器处理。我们无法利用#define创建一个class专属常量,因为#define并不重视作用域。一旦宏被定义,它就在其后的编译过程中由效(除非在某处被#undef)。这意味#define不仅不能够用来定义class专属常量,也不能够提供任何封装性,也就是说没有所谓private #define这样的东西。而当然const成员变量是可以被封装的。原创 2017-04-24 23:44:08 · 203 阅读 · 0 评论 -
读书笔记《Effective C++》条款06:若不想使用编译器自动生成的函数,就该明确拒绝
所有编译器产出的函数都是public。如果不想让编译器自动生成这些函数,得自行声明它们,可以将copy构造函数或copy assignment操作符声明为private,这样就阻止了编译器暗自创建的版本,而且令这些函数为private,得以成功阻止人们调用它们。一般而言这个做法并不绝对安全,因为member函数和friend函数还是可以调用private函数。有种办法:只声明这些private原创 2017-05-04 00:22:44 · 376 阅读 · 0 评论 -
读书笔记《Effective C++》条款28:避免返回handles指向对象内部成分
先看个例子。原创 2017-05-21 15:34:10 · 277 阅读 · 0 评论 -
读书笔记《Effective C++》条款22:将成员变量声明为private
要点:1.切记将成员变量声明为private。2.protected并不比public更具封装性。原创 2017-05-16 00:13:31 · 196 阅读 · 0 评论