高质量C++编程指南

  • 修饰符的位置,应将*和&紧靠变量名
int *x,y;//此处y不会被认为是指针变量,right
int* x,y;//此处y会被认为是指针变量,wrong
  • 在多重循环中,如果有可能,应当将最长的循环放在最内层,最短的循环放在最外层,以减少CPU跨切循环层的次数。  

  • 如何建立在整个类中都恒定的类成员变量?

不要指望const,比如有一个类成员变量const int a,因为不能在声明中初始化a,只能在构造函数中初始化它,而对于这个类的不同对象,可以初始化不同a值。要想使a在所有类对象中都恒定,可以使用枚举,enum { SIZE1 = 100, SIZE2 = 200};枚举常量不会占用对象的存储空间,它们在编译时被全部求值。枚举常量的缺点是:它的隐含数据类型是整数,其最大值有限,且不能表示浮点数。

  • 内存管理

内存分配方式有三种:

(1)从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量。

(2)在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。

(3)从堆上分配,亦称动态内存分配。程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存期由我们决定,使用非常灵活,但问题也最多。

指针与数组的对比:

C++/C程序中,指针和数组在不少地方可以相互替换着用,让人产生一种错觉,以为两者是等价的。数组要么在静态存储区被创建(如全局数组),要么在栈上被创建。数组名对应着(而不是指向)一块内存,其地址与容量在生命期内保持不变,只有数组的内容可以改变。指针可以随时指向任意类型的内存块,它的特征是“可变”,所以我们常用指针来操作动态内存。指针远比数组灵活,但也更危险。(注意:数组名是对应一块内存,而不是指向,两者有明显区别)

在修改内容时:

在内容复制与比较时:char a[]="hello";char b[10];b=a;不能通过编译,然而char *p = (char *)malloc(sizeof(char)*(strlen(a)+1));p=a;虽然在逻辑上是错误的,但是能通过编译。这是因为数组名是对应一块内存,而不是指向,当然不能简单通过=号赋值。也可以通过sizeof(a)=6,sizeof(char *)=4来证明此结论

有了malloc/free为什么还要new/delete 

malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符。它们都可用于申请动态内存和释放内存。对于非内部数据类型的对象而言,光用maloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free。 因此C++语言需要一个能完成动态内存分配和初始化工作的运算符new,以及一个能完成清理与释放内存工作的运算符delete。注意new/delete不是库函数。

  • C++的高级特性

对比于C语言的函数,C++增加了重载(overloaded)、内联(inline)、const和virtual四种新机制。其中重载和内联机制既可用于全局函数也可用于类的成员函数,const与virtual机制仅用于类的成员函数。

隐形类型转换导致二义性

void output(int x);void output(float x);//声明  output(0.5)//编译错误,由于数字本身没有类型,将数字当作参数时将自动进行类型转换,编译器不知道该将0.5转换成int还是float类型的参数。(像1和2之类的整数例外,编译器会把它们转为int型,如output(1)不会发生错误)

成员函数的重载、覆盖与隐藏

重载:在同一个类中,函数名相同,参数不同

覆盖:分别属于派生类和基类中,函数名和参数都相同,基类函数必须有virtual(也就是通常说的派生功能)

隐藏:它也是处于派生类和基类中(重点

(1)如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆)。

(2)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)。

 

内联

C++ 语言的函数内联机制既具备宏代码的效率,又增加了安全性,而且可以自由操作类的数据成员。所以在C++ 程序中,应该用内联函数取代所有宏代码,“断言assert”恐怕是唯一的例外

  • 类的构造函数,析构函数,赋值函数
类的const常量只能在初始化表里被初始化,因为它不能在函数体内用赋值的方式来初始化

基类的构造函数、析构函数、赋值函数都不能被派生类继承。如果类之间存在继承关系,在编写上述基本函数时应注意以下事项:

1.派生类的构造函数应在其初始化表里调用基类的构造函数。

2.基类与派生类的析构函数应该为虚(即加virtual关键字)。




posted @ 2012-02-08 11:28  南风又起  阅读(237)  评论(0编辑  收藏  举报