您的位置:首页 > 编程语言 > C语言/C++

<<C++程序设计与原理>> 笔记

2012-02-28 16:23 381 查看
不能直接识别的字面常量通常称为魔数(magic constant),要避免使用魔数;

299792458m/s :光在真空中的传播速度;

注意,编程能够让你理解世界上没有绝对确定的事情;

{……}称为程序块(block)或复合语句(compoundstatement);

注意,不要再for语句的循环体内修改循环控制变量的值.这种操作虽然没有语法错误,但是它违背了读者对于循环的普遍理解和认识;

为向量赋初值:

vector<int>v(6);

vector<string>philosopher>(4);

vector<double>vd(1000,-1.2);

//read some temperatures into a vector

int main()

{

vector<double>temps;

doubletemp;

while(cin>>temp)

temps.push_back(temp);

Sort(temps.begin(),temps.end());

for(inti=0;i<temps.size();++i)

cout<<”temps[<<i<<”]=”<<temps[i]<<endl;

//dosomething…

}

除非你有足够的理由,否则参数检查还是应该在函数内部完成;

C++提供的一种错误处理机制:异常.为了保证检测到的错误不会被遗漏,异常处理的基本思想是把错误检测(在被调函数中完成)和错误处理(在主调函数中完成)分离;

异常的基本思想是:如果函数发现一个自己不能处理的错误,它不是正常返回,而是抛出异常来表示错误的发生;

函数可以用try语句来处理异常:把所有要处理的异常情况罗列在catch语句后,如果出现一个没有被任何调用函数处理的异常,程序终止运行;

偏一位错误(off-by-one error);

范围错误(range error);

边界错误(bounds error);

基本上,我们可以认为计算机是一个速度非常快的笨蛋.它只是精确的完成你让它做的事情,这一点有时会让人感到很尴尬;

估计(estimation)是一种优雅的艺术,但有时候它会被(幽默地)称为瞎估计(guessimation);

下面是尽量避免调试的方法:

while(the program doesn’t appear to work){ //pseudo code

Randomlylook through the program for something that “looks odd”

Changeit to look better

}

在编码前一定要仔细考虑调试问题,首先要决定如何报告错误:”使用error()并在main()中捕获异常”应该是从本书中学到的一个标准答案;

注释的内容应该是你在代码里不能说清楚的的部分;

陈述一个不变式的语句称为断言(assertion或assertion);

有一件事要始终牢记:混乱的代码总是容易隐藏错误;

int area(int length, int width)

//calculate area of a rectangle;

//pre-conditions: length and width arepositive

//post-condition: returns a positive valuethat is the area

{

if(length<=0 || width<=0) error(“area()pre-condition”);

inta =length*width;

if(a<=0) error(“area() post-condition”);

returna;

}

“最后一个错误”是程序员之间的一个笑话:这种东西是不存在的;

好的测试人员的价值不亚于与他相同重量的黄金;

以冒号开始的特殊初始化语法(成员初始化列表)仅用于构造函数(constructor)中;

当面对一个棘手的技术问题时,通常都有一个标准答案,有经验的程序员就会咨询同事、查阅文献.希望猛冲猛闯,一夜之间打破50年来的经验是很愚蠢的想法;

请注意,我们如何一次又一次地避免做复杂的工作,代之以寻找简单的解决方案------通常是借助于C++库.这就是程序设计的本质:不断寻找更简单的方法;

只有当代码达到易于他人接管和维护的状态,程序才算是编写完成;

实际上,代码本身直接而又清晰的表达出的内容,是任何注释都无法表达清楚的.如果频繁的用注释来解释程序的含义,通常表明你的代码应该改进了;

一个名字的作用域越大,名字就该越长、越有描述性:将全局变量命名为x、y和f是灾难性的;

在函数声明中,形参的名字不是必需的,只是对于编写好的注释很有益处;

由于历史原因,main()是一个特例.执行到main()的末尾而未返回值,等价于返回0,意思是”成功完成”程序;

在一个不返回值的函数中,我们可以调用无值的return语句从函数返回调用者;

我们的根本原则是:

1) 使用传值方式传递非常小的对象.

2) 使用传常量引用方式传递你不需要修改的大对象.

3) 让函数返回一个值,而不是修改通过引用参数传递来的对象.

4) 只有迫不得已时才使用传引用方式.

只要你使用std_lib_facilities.h ,你就不需要担心标准库头文件和std名字空间了;

用户自定义类型(user-defined type, UDT);

类(class)成员默认是私有的;

一个结构(struct)就是一个成员默认为公有属性的类;

作为一名专业人员,编写这样的代码是不能赢得朋友和声望的;

判定有效值的规则称为不变式(invariant);

人们把公共接口放在类的开始,是因为接口是大多数人最感兴趣的;

我们应遵循如下基本原则:除非你明确需要从小函数的内联中获得性能提升,否则不要将成员函数放在类声明中成为内联的(inlined).对于5行以上代码的函数,不会从内联中获益;

一般性的原则是:除非你真正确定重载运算符能大大改善代码,否则不要为你的类型定义运算符;

就像大家一般猜想的那样,重载最多的运算符是+、-、*、/,而不是=、==、!=、<、[]及();

类的公有接口和实现部分应该分离;

当我们编程时,应该一直问自己:对于给定的应用,什么事足够好的解决方案?我们通常不会奢侈到,在已经的得到一个足够好的方案后,还会”无止境地”去追求最佳方案.继续追寻下去的话,我们甚至可能得到一些非常复杂,但却比最初的简单方案更差的方案.人们常说的”至善者善之敌”就是这个意思;

不访问类描述是很重要的,因为常用的debug技术是”首先排查惯犯”,即当类出现问题时,首先检查直接访问类描述的函数:几乎可以肯定是这类函数导致的错误;

cout<<”Please enter input file name:”;

string name;

cin>>name;

ifstream ist(name.c_str());

if(!ist) error(“can’t open input file ”,name);

//在打开一个文件之后,一定不要忘记检测是否成功了

vector<point>points;

Point p;

While(ist>>p) points.push_back(p);

cout<<”Please enter name of outputfile:”;

string oname;

cin>>oname;

ofstream ost(oname.c_str());

if(!ost) error(“can’t open output file “,oname);

for(int i=0; i<points.size(); ++i)

ost<<’(‘<<points[i].x<<’,’<<points[i].y<<”)\n”;

流状态:

good() 操作成功

eof() 到达输入末尾

fail() 发生某些意外情况

bad() 发生严重意外

记住,学习编写高质量代码的最好途径就是阅读大量代码

在不使用指针的情况下,使用好C++并不是容易的事;

删除空指针不会做任何事(因为空指针不指向一个对象),因此删除空指针是无害的;

一个”永远”运行的程序不能承受泄漏内存;

作为一个经验法则:如果你有一个带有虚函数功能的类,则它需要一个虚的析构函数;

除非你有一个删除对象的好的策略,尽量将new放在构造函数中,以及将delete放在析构函数中;

给一个对象名,所有的类都支持通过.(点)操作符来访问成员;与此类似,给定一个指针,所有类支持通过->(箭头)操作符来访问成员; .(点)和->(箭头)(通常称为成员访问操作符)可以用于数据成员和函数成员.由于内置类型(例如int和double)没有成员,因此->不能用于内置类型;

通常,一个实现了析构函数的类型同时也需要实现拷贝构造函数与拷贝赋值函数;

由关键字explicit修饰的构造函数(即显式构造函数)只能用于对象的构造而不能用于隐式转换;遗憾的是构造函数默认是非显式的;当我们拿不定主意时,我们最好将所有的具有一个参数的构造函数定义为显式构造函数;

我们应该尽可能地用vector类型取代数组;

不幸的是,由指针运算所造成的错误有时很难发现.通常最好的策略是尽量避免使用指针运算;

C++允许进行指针运算主要是因为历史原因(C语言),还有部分原因在于,在一些低层次的应用(例如内存管理器)中,使用指针运算更为便利;

将数组名转化为指针的一个原因在于避免将大量数据以传值的方式进行参数传递;

作为数组名向指针转换的一个结果,我们不能通过赋值操作拷贝数组;

只有字符数组能够通过字符串进行初始化,”在末尾加零”这一规则只适用于字符串;

不要用null指针进行数据访问;

对指针进行初始化;

不要访问不存在的数组元素;

不要通过一个已经进行delete操作的指针访问数据;

不要返回局部变量的的指针;

对于一个vector对象v, v.capacity()-v.size()代表了在不重新分配存储空间的前提下,我们通过push_back()操作能够向v添加元素的数量;

泛型编程:编写能够正确处理各种不同数据类型参数的代码,只要参数的数据类型满足特定的语法的语义的要求;

泛型编程有时也称为”面向算法的编程”;其设计的重点在于算法的实现而非算法所使用的数据类型;

RAII:资源获取即初始化(ResourceAcquisition Is Initialization)

《The C++ Programming Language》

我们需要提供一个对象以容纳vector<int>对象,以使得当异常发生时它能够销毁vector对象.为实现这一目标,在<memory>中标准库提供了auto_ptr:

vector<int>* make_vec() //make a filled vector

{

auto_ptr<vector<int>>p(new vector<int>; //allocate onfree store

//fillthe vector with data; this may throw an exception

Returnp.release(); //

}

auto_ptr对象是一个能够在函数中存储指针的对象,我们通过new返回的对象初始化auto_ptr对象,auto_ptr的用途是存储指针并保证在指针所指向对象的作用域结束时销毁该对象,auto_ptr的其他用途需要你掌握一些相当专业的知识;

STL(标准模板库standardtemplate library)通过序列(sequence)和迭代器(iterator)的概念将容器(数据)和算法(数据处理方法)关联起来;

标准库算法在<algorithm>头文件中声明;

除了vector之外,最有用的标准库容器恐怕就是map;

注意,当你将一个函数作为参数传递时,不要在其名字后面加上(),否则传递的将不是函数,而是其调用结果;

错误总是存在于你没有查看的地方------否则你早就找到它了;

KISS(Keep It Simple, Stupid,简单的才是最好的);

尽可能保持简洁,但不要过分简单化(Keep it simple, as simple as possible, but no simpler)—AlbertEinstein.

Fortran表示”公式转换”(FormulaTranslation)------被认为是第一个高级程序设计语言:由Fortran源码生成的机器码可以达到几乎最优的效率.时至今日,在数值计算优化领域,Fortran仍然处于领导地位;

COBOL(面向商业的通用语言,The CommonBusiness-Oriented Language)曾是面向商业应用程序员的主要语言(目前在某些情况下仍然是),主要用于数据处理;

Lisp主要用于链表和符号处理(也因此而得名,LIStProcessing),是解释型语言,目前最流行的版本是Common Lisp和Scheme;曾经是(现在也是)人工智能领域研究的支柱(虽然发布的产品通常是用C或者C++实现的).Lisp最主要的灵感源泉是λ演算(的数学思想);

Algol(ALGOrithmic Language)家族.”通用编程语言”的理念就源于Algol.Simula67和Pascal这两种语言是很多(几乎是所有的)现代语言的祖先;

Pascal源于Algol,但与Algol68不同,它是Algol60的简化;Pascal家族

Ada语言是为美国国防部专门设计的.特别的,它是一种适合于为嵌入式系统编写可靠、可维护程序的语言;Ada的设计目标是希望在程序设计语言中体现软件工程的思想;直到现在,Ada仍是航空应用程序和类似的高级嵌入式系统应用程序的重要编程语言;

Simula毫无疑问是Algol语言家族的成员,现在人们所说的”面向对象程序设计”的大多数基本思想都来自Simula.它是第一种提供继承和虚函数机制的语言;

C的魅力在于它是一种简单的编程语言,而这种简单性是慎重规划后的结果,而且C语言与硬件的基本特性关联非常紧密; C一直都与UNIX操作系统紧密联系在一起.近年来,又与Linux和开源项目的发展紧密相连;

C++最重要的发展就是STL---容器和算法的标准库;C和C++并不是计算领域中历史上最成功的两种语言,它们的强大在于灵活性、性能和稳定性;

正则表达式(简称正则式,”regexp”或”regex”)实际上是一种表达字符模式的语言.(它的一个子集就是使用最为广泛的一种方言PERL)

有一个程序员的谚语:”当你建立起一个万无一失的系统的时候,大自然会创造一个更傻的傻瓜来破坏它”.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: