自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(33)
  • 收藏
  • 关注

原创 Effective C++ 2e Item39

条款39: 避免 "向下转换" 继承层次在当今喧嚣的经济时代,关注一下我们的金融机构是个不错的主意。所以,看看下面这个有关银行帐户的协议类(Protocol class )(参见条款34):class Person { ... };class BankAccount {public:  BankAccount(const Person *primaryOwner,           

2001-07-31 22:13:00 1234

原创 Effective C++ 2e Item38

  条款38: 决不要重新定义继承而来的缺省参数值让我们从一开始就把问题简化。缺省参数只能作为函数的一部分而存在;另外,只有两种函数可以继承:虚函数和非虚函数。因此,重定义缺省参数值的唯一方法是重定义一个继承而来的函数。然而,重定义继承而来的非虚函数是一种错误(参见条款37),所以,我们完全可以把讨论的范围缩小为 "继承一个有缺省参数值的虚函数" 的情况。既然如此,本条款的理由就变

2001-07-31 22:12:00 1018

原创 Effective C++ 2e Item37

条款37: 决不要重新定义继承而来的非虚函数有两种方法来看待这个问题:理论的方法和实践的方法。让我们先从实践的方法开始。毕竟,理论家一般都很耐心。假设类D公有继承于类B,并且类B中定义了一个公有成员函数mf。mf的参数和返回类型不重要,所以假设都为void。换句话说,我这么写:class B {public:  void mf();  ...};class D: public B

2001-07-30 19:06:00 750

原创 Effective C++ 2e Item36

条款36: 区分接口继承和实现继承(公有)继承的概念看起来很简单,进一步分析,会发现它由两个可分的部分组成:函数接口的继承和函数实现的继承。这两种继承类型的区别和本书简介中所讨论的函数声明和函数定义间的区别是完全一致的。作为类的设计者,有时希望派生类只继承成员函数的接口(声明);有时希望派生类同时继承函数的接口和实现,但允许派生类改写实现;有时则希望同时继承接口和实现,并且不允许派生类改写

2001-07-30 19:05:00 868

原创 Effective C++ 2e Item35

继承和面向对象设计很多人认为,继承是面向对象程序设计的全部。这个观点是否正确还有待争论,但本书其它章节的条款数量足以证明,在进行高效的C++程序设计时,还有更多的工具听你调遣,而不仅仅是简单地让一个类从另一个类继承。然而,设计和实现类的层次结构与C语言中的一切都有着根本的不同。只有在继承和面向对象设计领域,你才最有可能从根本上重新思考软件系统构造的方法。另外,C++提供了多种很令人困惑的面

2001-07-29 18:38:00 747

原创 Effective C++ 2e Item34

条款34: 将文件间的编译依赖性降至最低假设某一天你打开自己的C++程序代码,然后对某个类的实现做了小小的改动。提醒你,改动的不是接口,而是类的实现,也就是说,只是细节部分。然后你准备重新生成程序,心想,编译和链接应该只会花几秒种。毕竟,只是改动了一个类嘛!于是你点击了一下"Rebuild",或输入make(或其它类似命令)。然而,等待你的是惊愕,接着是痛苦。因为你发现,整个世界都在被重新编译

2001-07-28 19:32:00 988

原创 Effective C++ 2e Item33

条款33: 明智地使用内联内联函数------多妙的主意啊!它们看起来象函数,运作起来象函数,比宏(macro)要好得多(参见条款1),使用时还不需要承担函数调用的开销。你还能对它们要求更多吗?然而,你从它们得到的确实比你想象的要多,因为避免函数调用的开销仅仅是问题的一个方面。为了处理那些没有函数调用的代码,编译器优化程序本身进行了专门的设计。所以当内联一个函数时,编译器可以对函数体执行特

2001-07-25 20:26:00 987

原创 Effective C++ 2e Item32

条款32: 尽可能地推迟变量的定义是的,我们同意C语言中变量要放在模块头部定义的规定;但在C++中,还是取消这种做法吧,它没必要,不自然,而且昂贵。还记得吗?如果定义了一个有构造函数和析构函数的类型的变量,当程序运行到变量定义之处时,必然面临构造的开销;当变量离开它的生命空间时,又要承担析构的开销。这意味着定义无用的变量必然伴随着不必要的开销,所以只要可能,就要避免这种情况发生。正如我

2001-07-25 20:24:00 820

原创 Effective C++ 2e Item31

条款31: 千万不要返回局部对象的引用,也不要返回函数内部用new初始化的指针的引用本条款听起来很复杂,其实不然。它只是一个很简单的道理,真的,相信我。先看第一种情况:返回一个局部对象的引用。它的问题在于,局部对象 ----- 顾名思义 ---- 仅仅是局部的。也就是说,局部对象是在被定义时创建,在离开生命空间时被销毁的。所谓生命空间,是指它们所在的函数体。当函数返回时,程序的控制离开了这

2001-07-23 20:24:00 908

原创 Effective C++ 2e Item30

条款30: 避免这样的成员函数:其返回值是指向成员的非const指针或引用,但成员的访问级比这个函数要低使一个成员为private或protected的原因是想限制对它的访问,对吗?劳累的编译器要费九牛二虎之力来确保你设置的访问限制不被破坏,对不对?所以,写个函数来让用户随意地访问受限的成员没多大意义,对不对?如果你确实认为有意义,那么请反复阅读本段,直到你不这样认为为止。实际编程中很容易

2001-07-23 20:23:00 1479

原创 Effective C++ 2e Item29

类和函数: 实现C++是一种高度类型化的语言,所以,给出合适的类和模板的定义以及合适的函数声明是整个设计工作中最大的一部分。按理说,只要这部分做好了,类、模板以及函数的实现就不容易出问题。但是,往往人们还是会犯错。犯错的原因有的是不小心违反了抽象的原则:让实现细节可以提取类和函数内部的数据。有的错误在于不清楚对象生命周期的长短。还有的错误起源于不合理的前期优化工作,特别是滥用inline关

2001-07-22 17:35:00 1019

原创 Effective C++ 2e Item28

条款28: 划分全局名字空间全局空间最大的问题在于它本身仅有一个。在大的软件项目中,经常会有不少人把他们定义的名字都放在这个单一的空间中,从而不可避免地导致名字冲突。例如,假设library1.h定义了一些常量,其中包括:const double LIB_VERSION = 1.204;类似的,library2.h也定义了:const int LIB_VERSION = 3;很

2001-07-22 10:14:00 888

原创 Effective C++ 2e Item27

条款27: 如果不想使用隐式生成的函数就要显式地禁止它假设想写一个类模板Array,它所生成的类除了可以进行上下限检查外,其它行为和C++标准数组一样。设计中面临的一个问题是怎么禁止掉Array对象之间的赋值操作,因为对标准C++数组来说赋值是不合法的:double values1[10];double values2[10];values1 = values2;           

2001-07-15 18:30:00 1187

原创 Effective C++ 2e Item26

条款26: 当心潜在的二义性每个人都有思想。有些人相信自由经济学,有些人相信来生。有些人甚至相信COBOL是一种真正的程序设计语言。C++也有一种思想:它认为潜在的二义性不是一种错误。这是潜在二义性的一个例子:class B;                    // 对类B提前声明                            // class A {public:  A(

2001-07-15 18:28:00 809

原创 Effective C++ 2e Item25

条款25: 避免对指针和数字类型重载快速抢答:什么是“零”?更明确地说,下面的代码会发生什么?void f(int x);void f(string *ps);f(0);                        // 调用f(int)还是f(string*)?答案是,0是一个int——准确地说,一个字面上的整数常量——所以,“总是”f(int)被调用。这就是问题所在:因为

2001-07-15 18:27:00 836

原创 Effective C++ 2e Item24

条款24: 在函数重载和设定参数缺省值间慎重选择会对函数重载和设定参数缺省值产生混淆的原因在于,它们都允许一个函数以多种方式被调用:void f();                             // f被重载void f(int x);f();                                  // 调用f()f(10);                 

2001-07-15 18:25:00 904

原创 Effective C++ 2e Item23

条款23: 必须返回一个对象时不要试图返回一个引用据说爱因斯坦曾提出过这样的建议:尽可能地让事情简单,但不要过于简单。在C++语言中相似的说法应该是:尽可能地使程序高效,但不要过于高效。一旦程序员抓住了“传值”在效率上的把柄(参见条款22),他们会变得十分极端,恨不得挖出每一个隐藏在程序中的传值操作。岂不知,在他们不懈地追求纯粹的“传引用”的过程中,他们会不可避免地犯另一个严重的错误:传递

2001-07-13 20:44:00 843

原创 Effective C++ 2e Item22

条款22: 尽量用“传引用”而不用“传值”C语言中,什么都是通过传值来实现的,C++继承了这一传统并将它作为默认方式。除非明确指定,函数的形参总是通过“实参的拷贝”来初始化的,函数的调用者得到的也是函数返回值的拷贝。正如我在本书的导言中所指出的,“通过值来传递一个对象”的具体含义是由这个对象的类的拷贝构造函数定义的。这使得传值成为一种非常昂贵的操作。例如,看下面这个(只是假想的)类的结构:

2001-07-13 20:43:00 891

原创 Effective C++ 2e Item21

条款21: 尽可能使用const使用const的好处在于它允许指定一种语意上的约束——某种对象不能被修改——编译器具体来实施这种约束。通过const,你可以通知编译器和其他程序员某个值要保持不变。只要是这种情况,你就要明确地使用const ,因为这样做就可以借助编译器的帮助确保这种约束不被破坏。const关键字实在是神通广大。在类的外面,它可以用于全局或名字空间常量(见条款1和47),以及

2001-07-12 20:14:00 832

原创 Effective C++ 2e Item20

条款20: 避免public接口出现数据成员首先,从“一致性”的角度来看这个问题。如果public接口里都是函数,用户每次访问类的成员时就用不着抓脑袋去想:是该用括号还是不该用括号呢?——用括号就是了!因为每个成员都是函数。一生中,这可以避免你多少次抓脑袋啊!你不买“一致性”的帐?那你总得承认采用函数可以更精确地控制数据成员的访问权这一事实吧?如果使数据成员为public,每个人都可以对它

2001-07-11 20:30:00 880

原创 Effective C++ 2e Item19

 条款19: 分清成员函数,非成员函数和友元函数成员函数和非成员函数最大的区别在于成员函数可以是虚拟的而非成员函数不行。所以,如果有个函数必须进行动态绑定(见条款38),就要采用虚拟函数,而虚拟函数必定是某个类的成员函数。关于这一点就这么简单。如果函数不必是虚拟的,情况就稍微复杂一点。看下面表示有理数的一个类:class Rational {public:  Rational(in

2001-07-10 21:21:00 2145

原创 Effective C++ 2e Item18

类和函数:设计与声明在程序中声明一个新类将导致产生一种新的类型:类的设计就是类型设计。可能你对类型设计没有太多经验,因为大多数语言没有为你提供实践的机会。在C++中,这却是很基本的特性,不是因为你想去做才可以这么做,而是因为每次你声明一个类的时候实际上就在做,无论你想不想做。设计一个好的类很具有挑战性,因为设计好的类型很具有挑战性。好的类型具有自然的语法,直观的语义和高效的实现。在C++中

2001-07-10 21:20:00 865

原创 Effective C++ 2e Item17

 条款17: 在operator=中检查给自己赋值的情况做类似下面的事时,就会发生自己给自己赋值的情况:class X { ... };X a;a = a;                     // a赋值给自己这种事做起来好象很无聊,但它完全是合法的,所以看到程序员这样做不要感到丝毫的怀疑。更重要的是,给自己赋值的情况还可以以下面这种看起来更隐蔽的形式出现:

2001-07-09 20:14:00 829

原创 Effective C++ 2e Item16

条款16: 在operator=中对所有数据成员赋值条款45说明了如果没写赋值运算符的话,编译器就会为你生成一个,条款11则说明了为什么你会经常不喜欢编译器为你生成的这个赋值运算符,所以你会想能否有个两全其美的办法,让编译器生成一个缺省的赋值运算符,然后可以有选择地重写不喜欢的部分。这是不可能的!只要想对赋值过程的某一个部分进行控制,就必须负责做赋值过程中所有的事。实际编程中,这意味着写赋

2001-07-08 19:36:00 868

原创 Effective C++ 2e Item15

条款15: 让operator=返回*this的引用C++的设计者Bjarne Stroustrup下了很大的功夫想使用户自定义类型尽可能地和固定类型的工作方式相似。这就是为什么你可以重载运算符,写类型转换函数(见条款M5),控制赋值和拷贝构造函数,等等。他做了这么多努力,那你最少也该继续做下去。让我们看看赋值。用固定类型的情况下,赋值操作可以象下面这样链起来:int w, x, y,

2001-07-08 19:35:00 942

原创 Effective C++ 2e Item14

条款14: 确定基类有虚析构函数有时,一个类想跟踪它有多少个对象存在。一个简单的方法是创建一个静态类成员来统计对象的个数。这个成员被初始化为0,在构造函数里加1,析构函数里减1。(条款M26里说明了如何把这种方法封装起来以便很容易地添加到任何类中,“my article on counting objects”提供了对这个技术的另外一些改进)设想在一个军事应用程序里,有一个表示敌人目标的类

2001-07-06 20:47:00 856

原创 Effective C++ 2e Item13

条款13: 初始化列表中成员列出的顺序和它们在类中声明的顺序相同顽固的Pascal和Ada程序员会经常想念那种可以任意设定数组下标上下限的功能,即,数组下标的范围可以设为10到20,不一定要是0到10。资深的C程序员会坚持一定要从0开始计数,但想个办法来满足那些还在用begin/end的人的这个要求也很容易,这只需要定义一个自己的Array类模板:templateclass Array {

2001-07-06 20:45:00 780

原创 Effective C++ 2e Item12

条款12: 尽量使用初始化而不要在构造函数里赋值看这样一个模板,它生成的类使得一个名字和一个T类型的对象的指针关联起来。templateclass NamedPtr {public:  NamedPtr(const string& initName, T *initPtr);  ...private:  string name;  T *ptr;};(因为有指针成员的对象在进行拷贝

2001-07-05 18:56:00 815

原创 Effective C++ 2e Item11

构造函数,析构函数和赋值操作符几乎所有的类都有一个或多个构造函数,一个析构函数和一个赋值操作符。这没什么奇怪的,因为它们提供的都是一些最基本的功能。构造函数控制对象生成时的基本操作,并保证对象被初始化;析构函数摧毁一个对象并保证它被彻底清除;赋值操作符则给对象一个新的值。在这些函数上出错就会给整个类带来无尽的负面影响,所以一定要保证其正确性。本章我将指导如何用这些函数来搭建一个结构良好的类的主

2001-07-05 18:54:00 981

原创 Effective C++ 2e Item10

 条款10. 如果写了operator new就要同时写operator delete让我们回过头去看看这样一个基本问题:为什么有必要写自己的operator new和operator delete?答案通常是:为了效率。缺省的operator new和operator delete具有非常好的通用性,它的这种灵活性也使得在某些特定的场合下,可以进一步改善它的性能。尤其在那些需要动态分

2001-07-04 20:31:00 1074

原创 Effective C++ 2e Item9

条款9. 避免隐藏标准形式的new因为内部范围声明的名称会隐藏掉外部范围的相同的名称,所以对于分别在类的内部和全局声明的两个相同名字的函数f来说,类的成员函数会隐藏掉全局函数:void f();                             // 全局函数class X {public:  void f();                           // 成员

2001-07-03 18:18:00 753

原创 Effective C++ 2e Item8

条款8. 写operator new和operator delete时要遵循常规自己重写operator new时(条款10解释了为什么有时要重写它),很重要的一点是函数提供的行为要和系统缺省的operator new一致。实际做起来也就是:要有正确的返回值;可用内存不够时要调用出错处理函数(见条款7);处理好0字节内存请求的情况。此外,还要避免不小心隐藏了标准形式的new,不过这是条款9的话

2001-07-02 21:01:00 1007

原创 Effective C++ 2e Item7

条款7:预先准备好内存不够的情况operator new在无法完成内存分配请求时会抛出异常(以前的做法一般是返回0,一些旧一点的编译器还这么做。你愿意的话也可以把你的编译器设置成这样。关于这个话题我将推迟到本条款的结尾处讨论)。大家都知道,处理内存不够所产生的异常真可以算得上是个道德上的行为,但实际做起来又会象刀架在脖子上那样痛苦。所以,你有时会不去管它,也许一直没去管它。但你心里一定还是深深

2001-07-02 16:25:00 1449 1

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除