Chinaunix首页 | 论坛 | 博客
  • 博客访问: 4235517
  • 博文数量: 176
  • 博客积分: 10059
  • 博客等级: 上将
  • 技术积分: 4681
  • 用 户 组: 普通用户
  • 注册时间: 2006-03-24 12:27
文章分类

全部博文(176)

文章存档

2012年(1)

2011年(4)

2010年(14)

2009年(71)

2008年(103)

分类: C/C++

2008-12-08 00:18:37

条款1:视C++为一个语言集合,有以下四个独立的部分

C++的内涵
(1) 继承C概念:区块,语句,预处理器,内置数据类型,数组,指针
(2) 对象概念: 类,封装,继承,多态,动态绑定
(3) 范型编程: 模板
(4) STL: template程序库,容器,迭代器,算法,function objects

 

条款2:用C++特性代替C中的预处理器

C预处理器:#include,#ifdef/#ifndef,#define
用C++特性代替#define 用途

#define用途(1): 定义常量
#define PI 3.14
替换为const double PI=3.14;
好处    (1)用define定义的常量没有进入记号表,不方便调试
        (2)用const定义常量将得到更精简的目标代码,因为预处理器处理#define是会盲目的将宏名称替换为3.14,若用const定义常量则不会出现这种问题。



当需要定义class专属常量的时候,不能用#define,因为#define并不重视作用域概念,而用const就可以定义class专属常量。


class Person
{
public:
    static const int SIZE = 1024;//这里只是声明,类内部的定义都是声明
    char name[SIZE];    //使用该常量
};

这里看到的 'SIZE' 只是声明式而非定义式。通常C++邀请你对你所使用的任何的东西都提供一个定义式,但是如果它是一个class专属常量又是static且为整数类类型(int,short,char,bool等)则需要特殊处理,只要不取它们的地址,你可以声明并使用它们而无须提供定义式。但如果你取某个class的专属常量的地址,或者你的编译器坚持要看到一个定义式(VC6就是这样),你就必须提供一个定义式如下:

const int Person::SIZE ;

C++中的两种替代方法:

(1) 使用static关键词
class GamePlayer{
private:
   static const int NumTurns=5;      //声明
   int scores[Numturns];
}

const int GamePlayer::NumTurns;     //定义

(2) 使用enum关键词
class GamePlayer{
private:
   enum{ NumTurns=5 };
   int scores[Numturns];
}


另外,enum和#define一样绝不会导致非必要的内存分配。

#define用途(2): 定义函数用途的宏
#define MAX(a,b) f((a)>(b)?(a):(b))
int a =5, b = 1;
MAX(++a, b);//a被累加二次
MAX(++a, b+10);//a被累加一次

替换为内联模板函数

template
inline void MAX(const T&a,const T&b)
{
      f(a>b?a:b);
}

好处:避免宏展开带来的不可靠影响


条款3:理解const关键字的深意,并把它运用到程序中去

如果const出现在星号左边,表示被指物是常量;如果const出现在星号右边,表示指针自身是常量。
如果出现在星号两边,表示被指物和指针两者都是常量。

(1)用const修饰变量、指针、迭代器等

表明迭代器不能被修改
例如:
vector vec;
const vector::iterator iter = vec.begin();
*iter = 10;//OK,没有问题
iter++;//错误,iter是一个const

vector::const_iterator cIter = vec.begin();
*cIter = 10;//错误,cIter指向的变量是一个const
cIter++;//OK,没有问题


(2)函数返回值声明为const,例如:
const Rational operator* (const Rational& lhs, const Rational& rhs)
作用:阻止if(a*b=c)等怪异的赋值语句

(3)const成员函数:
两个函数如果只是常量性不同,是可以被重载的。。

作用1:使class接口比较容易理解
     2:可以操作const对象
例子:
class TextBlock{
public:
     const char& operator[](size_t position) const
     {return text[position];}
     char& operator[](size_t position)
     {return text[position];}
private:
     string text;
};

void print(const TextBlock& ctb)
{
      cout<}

对于const函数的两种争论
(1)const函数不应该改变任何non-const数据成员(反例:如果有指针成员,还是能改变其所指对象)
(2)const函数可以改变数据成员,但必须在用户端无法检测到的情况下,这里还要要利用mutable技术

如何避免const成员函数和非const成员函数重载中的消耗问题
实现技术(1),用非const版本调用const版本
例子:
    const char& operator[](size_t position) const
    {
        return name[position];
    }
    char& operator[](size_t position)
    {
        return
           const_cast(    //将原来的op[]返回值的const转除
               static_cast(*this)[position]    //将non-const类型转换为const类型
           );
    }


(2)在类的private中增加一个函数,包涵所有公共代码

在const成员函数调用non-const成员函数是一中错误行为。


条款4:确定对象在使用之前初始化


成员初始化列表和函数内赋值的涵义
(1)对于类数据成员
成员初始化列表:调用类的copy构造函数进行初始化(高效)
函数内赋值:先后调用default构造函数和copy assignment操作符(低效)
(2)对于内置类型数据成员:两种方法效率相同
(3)保证对于所有内置数据类型进行手工初始化
(4)初始化列表中的排列次序要严格符合class中的声明次序,因为编译器永远按照成员变量的声明顺序来初始化,而不管初始化列表。

C++规定,对象的成员变量的初始化动作发生在构造函数本体之前。
C++对“定义于不同编译单元内的not-local static对象”的初始化次序并无明确定义
阅读(1407) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~