- 博客(48)
- 收藏
- 关注
原创 关于预处理器,编译器,汇编器,连接器的介绍与区别
,语法检查是编译器要做的事;(3)预处理之后,得到的仅仅是真正的源代码;(4)GCC确实很强大,如果是VC这种IDE,恐怕就不能看到预处理后的结果;
2024-02-02 13:02:02
1193
原创 条款48:认识template元编程
(1)Template metagropramming可将工作由运行期移往编译期,因为得以实现早期错误侦测和更高的执行效率;(2)TMP可被用来生成“基于政策选择组合”的客户定制代码,也可用来避免生成对某些特殊类型并不适合的代码。
2024-01-30 13:59:13
995
原创 条款47:请使用traits classes表现类型信息
(1)Traits classes使得“类型相关信息”在编译器可用。它们以template和“templates特化”完成实现。(2)整合重载技术后,traits classes有可能在编译器对类型执行if...else 测试。
2024-01-24 15:37:53
1270
原创 条款46:需要类型转换时请为模板定义非成员函数
当我们编写一个class template,而它所提供之“与此template相关的”函数支持“所以参数之隐式类型转换”时,请将那些函数定义为“class template内部的friend函数”。
2024-01-22 14:45:44
1007
原创 条款45:运用成员函数模板接受所有兼容类型
所谓智能指针(smart pointers)是”行为像指针“的对象,并提供指针没有的机能,比如条款13提到的std::auto_ptr和trl::shared_ptr如何被用来在正确时机自动删除heap-based资源。STL容器的迭代器几乎总是智能指针。但如果想在用户自动逸的智能指针中模拟上述转换,稍微有点麻烦。但。
2024-01-19 17:43:19
2125
原创 条款44:将与参数无关的代码抽离templates
(1)Template生成多个classes和多个函数,所以任何template代码都不该与某个造成膨胀的template参数产生联系;(2)因非类型模板参数而造成的代码膨胀,往往可以消除,做法是以函数参数或class成员变量替换template参数(3)因类型参数(type parameters)而造成的代码膨胀,往往可降低,做法是让带有完全相同二进制表述的具现类型共享实现码。
2024-01-18 14:04:01
1027
原创 条款43:学习处理模板化基类内的名称
假设我们需要编写一个程序,它能够传送信息到若干不同的公司去。信息要不编译称密码,要不就是未加工的文字。如果编译器间我们有足够的信息来决定哪一个信息传至哪一家公司,就可以采用基于template的解法:2.实例分析这个做法能够完成任务,但假设我们有时候想要在每次送出信息时log某些信息。derived class可轻易加上这样的功能:注意这里derived class的信息传送函数有一个不同的名称(sendClearMsg),与其base class内的名称(sendClear)不同。(能避免
2024-01-17 15:31:55
1902
原创 条款42:了解typename的双重意义
(1)声明template参数时,前缀关键字class和typename可互换;(2)请使用关键字typename标识嵌套从事类型名称;但不得在base class lists(基类)或member initialization list(成员初值列表)内以它作为base class修饰符。
2024-01-16 13:50:47
954
原创 条款41:了解隐式接口和编译器多态
(1)classes和templates都支持接口(interface)和多态(polymorphism)。(2)对classes而言接口都是显示的(explicit),以函数签名为中心。多态则是通过virtual函数发生于运行期。(3)对template参数而言,接口是隐式(implicit),奠基于有效表达式。多态则是通过template具现化和函数重载解析(function overloading resolution)发生于编译器。
2024-01-16 12:42:59
899
原创 条款40:明智而审慎地使用多重继承
(1)多重继承比单一继承复杂,可能会导致新歧义,以及对virtual继承的需要(2)virtual继承会增加大小,速度,初始化复杂度等成本。如果virtual base classes不带有任何数据,将是最有使用价值的情况(3)多重继承的确有应用价值。其中一个情节涉及“public继承某个Interface class”和“private继承某个协助实现的class”的两相组合。
2024-01-12 13:43:52
987
原创 条款39:明智而审慎地使用private继承
(1)private继承意味着is-implemented-in-terms of(根据某事实现出)。它通常比复合(conposition)的级别低。但是当derived class需要访问protected base class的成员,或需要重新定义继承而来的virtual函数时,这个设计是合理的。
2024-01-11 13:38:31
1205
原创 条款38:通过复合塑模出has-a或“根据某物实现出”
(1)复合的意义和public继承完全不同(2)在应用领域(application domain),复合意味着has-a(有一个)。在实现域,复合意味着is-implemented-in-terms-of(根据某物实现出)
2024-01-10 13:13:44
745
原创 条款37:绝不重新定义继承而来的缺省参数值
绝对不要重新定义一个继承而来的缺省参数值,因为缺省参数值都是静态绑定的,而virtual函数,唯一应该覆盖的东西,都是动态绑定的。每天都要加油呀呀呀呀!!!
2024-01-09 15:13:09
1018
原创 条款36:绝不重新定义继承而来的non-virtual函数
假设class D是由class B以public形式派生而来,class B定义有一个public成员函数mf,由于mf的参数和返回值都不重要,所以定义两者都为void。
2024-01-08 14:48:24
525
原创 条款35:考虑virtual函数以外的其它选择
本条款的根本忠告是当你为解决问题寻找某个设计方法时,不妨考虑virtual函数的替代方案。1.使用non-virtual interface方案,那是Template method设计模式的一种特俗形式。它以public non-virtual成员函数包裹较低访问性的virtual函数2.将virtual函数替换为“函数指针成员变量”,这是strategy设计模式的一种分解表现形式3.以trl::function成员变量替换virtual函数,因而允许使用任何可调用物搭配一个兼容于需求的签名式。
2024-01-05 17:57:48
1094
原创 条款34:区分接口继承和实现
综合以上内容,总结为以下几点:1.接口继承和实现继承不同,在public继承之下,derived classes总是继承base class的接口2.pure virtual函数只具体指定接口继承3.impure virtual函数具体指定接口继承及缺省实现继承4.non-virtual函数具体指定接口继承以及强制性实现继承。
2024-01-04 19:29:22
1231
原创 条款33:避免遮掩继承而来的名称
derived classes内的名称会遮掩base classes内的名称,在public继承下从来没有人会希望这样;为了让被遮掩的函数或变量被调用,可以使用using声明式或转交函数。
2023-12-28 13:35:03
1038
原创 条款32:确定你的public继承塑模出is-a关系
以c++进行面向对象编程时,最重要的一个规则是:public inheritance(公开继承)意味着“is-a”的关系。
2023-12-27 13:52:29
1013
原创 条款31:将文件间的编译依存关系降低到最低
支持“编译依存性最小化”的一般构想是:相依于声明式,不要相依于定义式。基于此构想的两个手段是Handle classes 和Interface classes.程序库头文件应该以“完全且仅有声明式”的形式存在。这种做法无论是否涉及templates都适用。
2023-12-24 12:28:55
958
原创 条款30:透彻了解inlining的里里外外
将以上内容总结为以下两点:1.将大多数inlining限制在小型,被频繁调用的函数身上。这可使得日后的调试过程和二进制升级更容器,也可使得潜在的代码膨胀问题最小化,使程序的速度提升机会最大化。2.不要只因为function template出现在头文件,就将它们声明为inline.
2023-12-19 15:34:47
997
原创 条款28:避免返回handles指向对象内部成分
由于内容较多,对本文的内容总结为以下几点:1.避免返回handles(包括references,指针,迭代器)指向对象内部。遵守这个条款可以增加封装性,帮助const成员函数的行为像个const,并将发生dangling handles的可能性降到最低。
2023-12-18 13:55:40
1039
原创 条款27:尽量少做转型动作
1.如果可以,尽量避免转型,特别是在注重效率的代码中避免dynamic_cast,如果有个设计需要转型动作,尝试发展无需转型的替代设计。2.如果转型是必要的,试着将它隐藏在某个函数背后。客户随后可以调用该函数,而不需要将转型放进它们的代码内;3.一旦不得不使用转型,宁可使用c++style新式转型,不要使用旧式转型。前者很容易辨识出来,而且也相对职责分明。
2023-12-17 12:00:54
1080
原创 条款26:尽可能延后变量定义式的出现时间
只要定义了一个变量而该变量的类型带有一个构造函数或析构函数,那么当程序的控制流到达这个变量定义式时,你便得承受构造成本;当这个变量离开其作用域时,你便得承受析构成本。即使这个变量最终并未被使用,仍需耗费这些成本,所以应该尽可能避免这种情形。
2023-12-13 11:53:46
729
原创 条款25:考虑写出一个不抛出异常的swap函数
swap是个有趣的函数,原本它只是STL的一部分,而后成为异常安全编程的基石,以及用来处理自我赋值可能性的一个常见机制。由于swap功能如此强大,适当的实现很重要。然而在非凡的重要性之外它也带来了非凡的复杂度。所谓swap两对象值,意思是将两对象的值彼此赋予对方。缺省情况下swap动作可由标准程序库提供的swap算法完成。只要类型T支持copying(通过copy构造函数和copy assignment操作符完成),缺省的swap实现代码就会帮你置换类型为T的对象,不需要为此做另外的工作。
2023-12-11 15:30:10
439
原创 条款24:若所有参数都需类型转换,请为此采用non-member函数
令classes支持隐式类型转换通常是个糟糕的想法,当然这条规则有其例外,最常见的例外是在建立数值类型时候,假如你设计一个class用来表现有理数,允许整数“隐式转换”为有理数似乎颇为合理。
2023-12-06 13:44:39
1005
原创 条款23:宁以non-member,non-friend替换member函数
那么,哪一个比较好呢?是member函数clearEverything还是non-member函数clearBrowser?根据面向对象的准则,数据以及操作数据的这些函数应该绑定在一起,这意味着建议member函数是较好的选择。然而事实是这个建议不正确,那是对面向对象真实含义的误解。面向对象守则要求数据尽可能被封装,然而与直观相反,member函数clearEverything带来的封装性比non-member函数clearBrowser低。
2023-12-03 17:58:17
923
原创 条款22:将成员变量声明为private
(1)切记将成员变量声明为private,这可赋予客户访问数据的一致性,可细微划分访问控制。允诺约束条件获得保证,并提供class作者以充分的实现弹性。(2)protected并不比public更具封装性。
2023-12-02 01:57:23
448
原创 条款21:必须返回对象时,别妄想返回其reference
一旦程员意识到pass-by-value的效率问题,往往就会陷入一种误区,一心一意根除pass-by-value带来的种种问题。在坚定追求pass-by-reference的路上,肯定会进入一个误区,即:开始传递一些references指向不存在的对象。这可不是件好事。考虑一个用以表现有理数的class,内含一个函数用来计算两个有理数的乘积: 这个版本的operator* 是以by value方式返回其计算结果(一个对象),如果改而传递reference,就不需要考虑构造函数和析构函数带来的开销。但是
2023-11-28 23:34:19
893
原创 条款20:宁以pass-by-reference-to-const替换pass-by-value
缺省情况下C++以by value方式传递对象至函数。除非另外指定了,否则函数参数都是以实际实参的副本为初值,而调用端所获得的亦是函数返回值的一个副本。这些副本是由对象的copy构造函数产出,这导致pass-by-value成为费时的操作。当上述程序代码运行时,发生什么事情呢?首先,Student的copy构造函数会被调用,以plato为蓝本将s初始化。同样明显地,当validateStudent返回,s会被销毁。
2023-11-24 16:23:21
1581
1
原创 条款19:设计class犹如设计type
如果继承自某些即有的classes,就受到那些classes的设计束缚,特别是受到“它们的函数是virtual或non-virtual”的影响。如果允许其他classes继承你的class,那么影响你所声明的函数-特别是析构函数是否为virtual。它对效率,异常安全性以及资源运用提供何种保证?在这些方面提供的保证将为你的class内的代码加上相应的约束条件。
2023-11-22 14:18:06
1072
原创 条款3:尽可能使用const
const允许指定一个语义约束,而编译器会强制实施这项约束。即告诉编译器和其他程序员这项值应该保持不变。关键字const可以用于多个领域。你可以将它应用于classes外部修饰global或namespace作用域中的常量,或修饰文件。函数。或区块作用域中被声明为static的对象。也可以把它修饰classes内部的static或non-static成员变量。
2023-11-20 15:07:02
269
1
原创 条款02:尽量以const,enum,inline替换#define
看这个名称,顾名思义,或许更改为“宁可以编译器替换预处理器”更好,因为#define不被当作语言的一部分,这正是它的问题所在。在上面代码中,记号名称ASPECT_RATIO也许从未被编译器看见。也许在编译器开始处理源码之前该名称就被预处理器转移走了。导致记号名称ASPECT_RATIO有可能没进入记号表内。于是在运用此常量但获得一个编译错误信息时,可能会带来困惑,因为这个错误信息会提到1.653,而不是ASPECT_RATIO。
2023-11-17 14:14:26
178
原创 条款4:确定对象被使用前已被初始化
关于将“对象初始化”这事,似乎很多人觉得没什么值得注意的地方。int x;在某些语境下x保证被初始化为0,但在其他语境中却不能得到保证。在这里,p的成员变量有时候会被初始化为0,有时候不会。读取未初始化的值会导致不明确行为。在某些平台,仅仅市读取未初始化的值,就可能让你的程序终止。而最好的处理办法是:永远在使用对象之前先将它初始化。对于无任何成员的内置类型,必须手动完成这件事。对于内置类型以外的其它成员变量,初始化责任落在构造函数身上。规则很简单:确保每一个构造函数都将对象的每一个成员初始化。
2023-11-15 14:33:29
606
原创 条款18:让接口容易被正确使用,不易被误用
C++合理的程序代码中,有很多接口:function接口,class接口,template接口....,每一个接口都是与代码互动的手段。要开发一个“容易被正确使用,不容易被误用”的接口,首先需要考虑客户可能做出什么样的错误。表面一看,这个接口合情合理可,但使用它的人员容易犯下以下错误:1.会以错误的次序传递参数;2.传递一个无效的月份或天数;
2023-11-14 14:09:37
147
原创 条款12:复制对象时勿忘其每一个成分
合格的面向对象系统会将对象的内部封装起来,只留下两个函数负责对象拷贝,即copy构造函数和copy assignment操作符,我统一称它们为copying函数。如果在class类里面声明自己的copy函数,意味着告诉编译器并不喜欢编译器自动生成的copy构造函数。此时编译器会u彷佛被冒犯,会以一种奇怪的方式回敬:当你的代码几乎必然出错时却不告诉你。。但大多数编译器对此并不作出任何警报,因为程序员自写了copy构造函数。
2023-11-13 14:55:59
284
原创 条款11:在operator=处理“自我赋值”
这种代码逻辑看上去有点笨笨的,但是合法的代码。如果i和j有相同的值时候,这便是哥自我赋值。在此处,如果px和py恰巧指向的是同一个东西,这也是自我赋值的一种。一般而言如果某段代码操作pointer或reference被用来“指向多个相同类型的对象”,就需要考虑这些对象是否为同一个。当运用对象来管理资源,能保证赋值操作符在“自我赋值是安全的”,不需要额外操心。但是当运用自我管理的方式,可能会掉进“在赋值之前已经把赋值对象给删除了”的陷进。
2023-11-10 14:05:57
190
1
原创 条款10:令operator=返回一个reference to *this
关于赋值,有趣的是你可以把它们写成连锁形式:根据原理,赋值采取右结合律,所以上述连锁赋值被解析为:这里的赋值顺序为15先赋给z,更新后的z再赋值给y,最后更新后的y再赋值给x。为了实现“连锁赋值”,赋值操作符必须返回一个reference指向操作符的左侧实参。即:该协议不仅适用于以上的标准赋值,也适用于所有赋值相关运算。如:2.operator的拓展operator是C++的关键字,其主要有两个作用,一是运算符重载,通常它和运算符配合使用,表示一个运算符函数,理解时应将opera
2023-11-09 14:27:45
127
1
原创 条款9:绝不在构造和析构过程中调用virtual函数
同样,相同的原理也适应于析构函数。一旦derived class析构函数开始执行,对象内的derived class成员变量便呈现未定义值。进入base class析构函数后对象就成为一个base class对象。在上述示例中,Transaction构造函数直接调用一个virtual函数,这很明显与本条款冲突。
2023-11-08 15:03:47
833
1
原创 条款8:别让异常逃离析构函数
C++并不禁止析构函数吐出异常,但是不鼓励出现这种情况。在上述代码中,当vector v被销毁时,它有责任销毁其内含的所有Widgets。假设v内含十个Widgets,而在析构第一个元素期间,有个异常被抛出。其他9个Widgets还是应该被销毁(否则它们保存的任何资源都可能发生资源泄露),因此v会调用它们各个析构函数。但假设在那些调用期间,第二个Widget析构函数又抛出异常。现在有两个同时作用的异常,这对C++而言太多了,因为在两个异常同时存在的情况下,程序不是结束执行,就是出现不明确行为。
2023-11-07 14:26:22
171
原创 条款07:为多态基类声明virtual析构函数
在程序编写时,程序员只想在程序中使用时间,而不想操心时间如何被计算等这些细节,这时候我们可以设计factory(工厂)函数,返回指针指向一个计时对象。为遵守factory函数的规矩,被getTimeKeeper()返回的对象必须位于heap。任何一个class只要带有virtual函数都几乎确定应该有一个virtual析构函数。
2023-11-03 14:06:00
309
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人