C++
老火
这个作者很懒,什么都没留下…
展开
-
《Thinking in C++, 2nd Edition》笔记-第二章(Making & Using Objects)
1 解释器和编译器所有的计算机语言都从人类了解的语言(源代码)翻译成机器上可以执行的东西,传统上这种翻译分成两类:解释型语言和编译型语言。解释型语言的实现中,解释器从源代码产生易于执行的中间代码,并且可以由解释程序立即执行。它的优点时从写代码到执行代码几乎是即时的,而且因为有源代码,错误发生时容易找到错误。缺点是每执行一次就翻译一次,因而效率低下,而且大多数翻译器要求一次性加载入所有的源文原创 2013-04-05 16:32:33 · 626 阅读 · 0 评论 -
《Thinking in C++, 2nd Edition》笔记-第十七章(Multiple inheritance)
多重继承MI(multiple inheritance):通过继承多个基类来生成一个新类。只要继承图简单,MI应该也不复杂。但是MI会引入许多二义性和奇怪的现象。子对象重复派生类从基类继承时,派生类中就获得了基类所有数据成员的副本,该副本称为子对象。假若对类d1和类d2进行多重继承而形成类mi,类mi会包含d1的子对象和d2的子对象,所以mi对象看上去如下面左图所示。原创 2013-04-15 21:09:25 · 676 阅读 · 0 评论 -
《Thinking in C++, 2nd Edition》笔记-第十六章(Introduction to Templates)
模板的引入继承和组合提供了重用对象代码的方法,而模块提供重用源代码的方法。一个容器是可以容纳其它对象的对象。它允许向它存储对象,而后可以取出使用的高速、智能的暂存存储器。容器类是解决不同类型的代码重用问题的另一种方法。#include using namespace std; class IntStack { enum { ssize = 100 }; int stac原创 2013-04-15 10:44:03 · 602 阅读 · 0 评论 -
《Thinking in C++, 2nd Edition》笔记-第十八章(Exception handling)
C语言中,出错信息通常通过函数的返回值来获得,或者通过设置全局的错误判断标志(标准C语言中的errno()和perror()),对每个函数的返回值进行错误检查会使程序变得繁琐,程序设计者可能简单的忽略这些出错信息。而C++的异常处理,1) 出错处理程序的编写不再繁琐,也不需要将出错处理程序与正常代码紧密结合。在错误有可能出现的地方写一些代码,并在后面的语句中加入出错处理程序。如果程序中多次调用原创 2013-04-16 16:26:21 · 528 阅读 · 0 评论 -
《Thinking in C++, 2nd Edition》笔记-第十九章(Run-time type identification)
只有一个基类指针或引用的时候,可以通过运行时类型识别(RTTI)来确定这个对象的准确类型。在C++中加入异常处理功能时,它的实现要求在虚函数表中加入一些运行时类型信息。RTTI与异常一样,依赖于虚函数表中的类型信息,因此,没有虚函数表的类上用RTTI,会得到不可预知的结果。RTTI的两种使用方法使用RTTI有两种不同的方法。第一种就像sizeof(),它看上就像一个函数,但实际上它是由原创 2013-04-17 10:14:15 · 464 阅读 · 0 评论 -
纯虚类的析构函数的问题
class IA{public: virtual void Test() = 0; virtual void Release() = 0;};Review同事代码的时候,看到声明了接口类的析构函数,然后后面是一个空实现:class IA{public: virtual void Test() = 0; virtual ~IA(){}};觉得有点别扭,按道理原创 2013-05-23 16:23:03 · 699 阅读 · 0 评论 -
《Thinking in C++, 2nd Edition》笔记-第一章(Introduction to Objects)
Alan Kay总结的SmallTalk(第一个成功的OO语言,C++发展的基础之一)的五个特性:1.一切事物都是对象。把对象想象成一个变量,它存储数据,又可以向它提出请求,让它自己执行操作。理论上,可以把任何需要解决的问题的概念成分看成一个对象。2.一个程序是一组通过发送消息告知彼此干什么的对象组成。3.每个对象都有自己的内存,由其它的对象组成。4.每个对象都有一个类型,对象是一原创 2013-04-04 13:10:57 · 644 阅读 · 0 评论 -
《Thinking in C++, 2nd Edition》笔记-第三章(The C in C++)
1 函数参数在早期的C语言中,你可以用随意的用任何数量和类型的参数来调用函数,编译器不会不允许。标准的C&C++使用了一个叫函数原型的特性。在声明和定义函数时,必须指定函数的参数类型和返回值类型,在调用时如果参数或返回值不对,编译器会提示错误。以下两种函数声明都是允许的:int translate(float x, float y, float z);int translate原创 2013-04-06 15:04:39 · 528 阅读 · 0 评论 -
为何不能过多的使用内联(为何有时内联无法提升性能)?
内联带来的性能提升?1、避免开销大的方法调用。2、调用间优化。某一方法的调用过程,基于对上下文场景更加全面的理解,使得编译器在源代码层面及机器代码层面对方法进行优化。为啥不能内联全部方法?1、内联所带来的代码膨胀有时是无法接受的。2、单个内联方法拥有多个实例,每个实例都要有自身的地址空间,因此它们消耗的缓存也相互独立,这样将减少有效的缓存空间而造成命中率下降。而且,内联原创 2013-08-24 21:37:39 · 574 阅读 · 0 评论 -
《Thinking in C++, 2nd Edition》笔记-第十五章(Polymophism & Virtual Functions)
函数调用绑定如果一个子类指针向上转型为基类指针,然后用这个基类指针调用某个函数,那么调用的将会是基类版本的函数,但是其实它是一个子类类型,理应调用子类版本的函数应该更合理。这是因为编译器在只有一个基类指针的时候并不知道调用正确的函数,它是早绑定。将函数调用连接到函数体叫做绑定。在程序运行之前由编译器执行的绑定叫做早绑定。基于对象的类型,在运行时执行的绑定叫做晚绑定,也叫动态绑定或运行时绑定原创 2013-04-14 13:40:41 · 700 阅读 · 0 评论 -
《Thinking in C++, 2nd Edition》笔记-第十三章(Dynamic Object Creation)
对象创建C提供了动态内存分配函数malloc()和free(),在运行时从堆中分配存储单元,但是在C++中作用有限:对象不能初始化,而对象的构造函数又不允许向它传递内存函数来初始化它。因此,C++通过new和delete运算符来使我们能够完成动态内存分配及初始化,清理及释放内存。当一个C++对象被创建时:1)为对象分配内存。2)调用构造函数来初始化内存。对于2)未初始化的对象是原创 2013-04-13 08:39:50 · 718 阅读 · 0 评论 -
《Thinking in C++, 2nd Edition》笔记-第十四章(Inheritance & Composition)
什么是继承和组合组合:一个类中将另一个类的对象作为成员,是has-a关系class X { int i;};class Y{ int i; X x;};继承,is-a关系class X { int i;};class Y : public X { int i;};实际上Y继承自X,意味着Y原创 2013-04-13 13:50:22 · 674 阅读 · 0 评论 -
《Thinking in C++, 2nd Edition》笔记-第四章(Data Abstraction)
头文件的使用1 将什么放进头文件中?基本规则是“只声明”,也就是说,对于编译器只需要一些信息以产生代码或创建变量分配内存。因为在一个项目中,头文件也许会包含在几个处理单元中,而如果内存分配不止一个地方,则连接器会产生多重定义错误。这个规则不是非常严格的。如果在头文件中定义“静态文件”的一段数据(只在文件内可见,比如const变量),在这个项目中将有这个数据的多个实例,编译器不会报错。基本上原创 2013-04-06 17:11:56 · 560 阅读 · 0 评论 -
《Thinking in C++, 2nd Edition》笔记-第五章(Hiding the Implementation)
C++的存取控制public:在其后声明的所有成员对所有的人都可以存取private:除了该类型的创建者和类的内部成员函数之外,任何人都不能存取这些成员。protected: protected与private基本相似,只有一点不同:继承的结构可以访问protected成员,但不能访问p r ivat e成员。 友元如果程序员想允许不属于当前结构的一个成员函数存取结构中的数原创 2013-04-08 19:36:57 · 526 阅读 · 0 评论 -
《Thinking in C++, 2nd Edition》笔记-第七章(Function Overloading & Default Arguments)
为什么需要函数重载。大多数编程语言要求我们为每个函数设定一个唯一的标识符。如果我们想打印三种不同类型的数据:整型、字符型和实型,我们通常不得不用三个不同的函数名,如print _ int( )、print _ char( )和print _ float( ) ,这些既增加了我们的编程工作量,也给读者理解程序增加了困难。在C++中,还有一个重要原因需要我们对函数重载:构造函数。因为构造函数的名字原创 2013-04-08 19:43:26 · 530 阅读 · 0 评论 -
《Thinking in C++, 2nd Edition》笔记-第六章(Initialization & clean up)
在C++中,初始化和清理的概念是简化类库使用的关键,并可以减少那些由于用户忘记这些操作而引起的许多细微错误。用构造函数保证初始化,析构函数保证清除如果一个类有构造函数,编译器在创建对象时就自动调用这一函数。对用户来说,是否调用构造函数并不是可选的,它是由编译器在对象定义时完成的。构造函数的名字?最容易也最合乎逻辑的是:构造函数的名字与类的名字一样。这使得这样的函数在初始化时自动被调用。原创 2013-04-08 19:38:00 · 500 阅读 · 0 评论 -
《Thinking in C++, 2nd Edition》笔记-第八章(Constants)
值替换const的最初动机是消除使用预处理器#define对常量的替换。#define只是对文本进行替换并且没有类型检查,因此会产生一个隐藏的问题,而这些用const可以避免。例如:const int bufsize = 100; 可以在任何需要知道这个值(100)的地方使用bufsize,编译器会进行常量折叠(常量折叠是在编译时间简单化常量表达的一个过程。简单来说就是将常量表达式计原创 2013-04-08 19:44:14 · 426 阅读 · 0 评论 -
《Thinking in C++, 2nd Edition》笔记-第九章(Inline Functions)
在C中,宏可以用来提高效率,宏的实现是用预处理器而不是编译器。预处理器直接用宏代码代替调用,所以就没有了参数压栈、生成汇编语言的CALL、返回参数、执行汇编语言的RETURN的时间花费。所有的工作由预处理器完成,因此,不用花费什么就具有了程序调用的便利和可读性。C++中,使用预处理器宏存在两个问题。第一个问题在C中也存在:宏看起来像一个函数用,但并不总是这样。这就隐藏了难以发现的错误。第二个问题是原创 2013-04-09 21:12:02 · 498 阅读 · 0 评论 -
《Thinking in C++, 2nd Edition》笔记-第十一章(References & the Copy-Constructor)
C++中的指针C++是一种更强类型的语言,比如void*,C中不允许一种类型指针赋值给另一种类型指针,但是可以通过void*来实现:bird* b; rock* r; void* v; v = r; b = v;而在C++中这种转换必须用显示的类型转换才行。C++中的引用引用就像是能被编译器自动解引用的指针。1)引用在创建时必须被初始化。(指针可以在任何时候原创 2013-04-10 22:18:33 · 635 阅读 · 0 评论 -
《Thinking in C++, 2nd Edition》笔记-第十章(Name Control)
static关键字有时控制存储分配,而有时控制一个名字的可见性和连接。它的含义因此经常是相互冲突的:(1)在静态数据区上创建对象,而不是每次函数调用时在堆栈上产生。这也是静态存储的概念。如果想在两次函数调用之间保留一个变量的值,我们可以通过定义一个全局变量来实现这点,但这样一来,这个变量就不仅仅受这个函数的控制,还受其它函数影响。C和C++都允许在函数内部创建一个static对象,这个对象原创 2013-04-10 14:52:38 · 564 阅读 · 0 评论 -
《Thinking in C++, 2nd Edition》笔记-第十二章(Operator Overloading)
运算符重载只是一种“语法修饰”,本质上也是函数,只不过它的参数不出现在括号之内,而是出现在运算符附近。因此除非重载运算符使程序变得易写,尤其是更易读,否则就不必去重载运算符。比如说,不能像重载 1重载运算符就像定义一个函数,函数名字为operator@,其中@代表运算符。运算符参数表中的参数取决于:(1)运算符是一元(一个参数)还是二元(两个参数);(2)运算符是全局(对于一元是一个参数,对于原创 2013-04-12 11:34:05 · 730 阅读 · 0 评论 -
编码优化
同深层次的设计问题相比,性能方面的编码问题更容易解决,这些问题的规模通常较小,在其解决方法中,所包含的代码量都很小。1 缓存缓存主要用来存储使用频繁而且代价高昂的计算结果,这样就可以避免对这些结果的重复计算。for(...; !done; ...){ done = patternMatch( pat1, pat2, isCaseSensitive() );}由于isCase原创 2013-08-29 22:17:39 · 667 阅读 · 0 评论