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

(Effective C++)第一章 让自己习惯C++(View Yourself to C++)

2011-10-15 19:33 579 查看

1.1 条款1:视C++为一个语言联邦(View C++ as a federation of language)

C++主要的次语言(sublanguage):

l  【3-1-1】 说到底C++仍是以C为基础。区块(blocks),语句 (statements),预处理器(preproccessor),内置数据类型(built-in data types),数组(arrays),指针(pointers)等都来自于C。

l  【3-1-2】 Object-Oriented C++.类classes,封装(encapsulation),继承(inheritance),多态(polymorphism),virtual函数(动态绑定)等等

l  【3-1-3】 Template C++这是泛型编程(genericprogramming)部分,它带来了崭新的编程范型(programming paradigm),也就是所谓的template metaprogramming(TMP,模板元编程)。

l  【3-1-4】 STL是个template程序库。它对容器(containers),迭代器(iterators),算法(algorithms)以及函数对象(function objects)。

1.2 条款2:尽量使用consts,enums和inlines,少用#define (Prefer consts,enums and inlines to #define)

在C++程序中,尽量使用consts,enums和inlines,少用#define。

l  【3-2-1】对于单纯常量,最好以const对象或enum替换#defines。

l  【3-2-1】对于形似函数的宏(macros),最好改用inline函数。

例如:

const double PAI = 3.1415;

const char* const HELLO = "Hello";

const std::string AUTHOR_NAME = "wuzhenghua";

class CAnimal

{

     Private:

         const int COLOR = 1;

};

示例3-2-1 常量

我们无法利用宏#define创建一个class专属常量,因为#define并不重视作用域(scope)。

一个属于枚举类型的数值可以冒充ints使用。枚举的行为比较像#define而不像const。例如,取一个const的地址是合法的,但是取一个enum的地址就不合法,而取#define的地址也是不合法的。

#define函数一是语句引起的歧义,二是没有安全类型检查。所以最好使用inline函数,如下:  

template<typename T>

Inline  void MAX(const T& a, const T &b)

{

    f(a > b ? a:b);

}

示例3-2-2 inline函数

1.3 条款3:尽可能使用const(Use const wheneverpossible)

Const的一件奇妙事情是,它允许你指定一个语义约束(也就是指定一个“不被改动”的对象),而编译器会强制实施这项约束。

1.3.1 const与指针
面对指针,修饰指针,或修饰指针所指物。如果关键值const出现在星号左边,表示被指物是常量;如果出现在星号右边,表示指针自身是常量;如果出现在星号两边,表示两者都是常量。

char greeting[]="Hello";

char *p = greeting;                 //non-const pointer, non-const data

const char *p = greeting;           //non-const pointer, nconst data

char * const p = greeting;          //const pointer, non-const data

const char * const p = greeting;    //const pointer, const data

示例3-3-1 const与指针变量

1.3.2 const与迭代器
如果你希望迭代器所指的东西不可被改动(即是希望STL模拟一个const T* 指针),你得使用const_iterator:   

std::vector<int> vec;

const std::vector<int>::iterator iter = vec.begin(); // iter像T*const

*iter = 10;       //正确

iter++;           //错误

std::vector<int>::const_iterator cIter = vec.begin();// iter像const T*

*cIter = 10;       //错误

cIter++;           //正确

示例3-3-2 const与迭代器

令函数返回一个常量值,可以降低因客户错误而造成的意外,而不置于放弃安全性和高效性。

class Rational {…};
const Rational operator*(const Rational& lhs, const Rational & rhs);

Rational a,b,c;       //正确

if(a*b=c)  //其实想做一个比较而掉了一个=,编译器报错

示例3-3-3 const与operator*

1.3.3 const与成员函数

理由:第一,const是class接口比较容易被理解;第二,const使“操作const对象”成为可能。两个成员函数如果只是常量性(constness)不同,可以被重载。这是C++的一个重要特性。const成员函数不可以更改对象内任何non-static成员变量。

const与non-const成员函数应该避免代码重复。

Class TextBlock {

public:



const char & operator[](std::size_t pos) const

{

   …

}

char & operator[](std::size_t pos)

{

   return const_cast<char &>  //将op[]返回值的const去除

          (static_cast<const TextBlock &>(*this) //为*this加上const

          [pos];

}



}

示例3-3-4 const与成员函数

【注意】 non-const成员函数本来就可以对其对象做任何动作,所以在其中调用一个const成员函数并不会带来风险。

1.4 条款4:关于“将对象初始化”这事,C++似乎反复无常(Make sure that object areinitialized before they’re used)

关于“将对象初始化”这事,C++似乎反复无常。

确保每个构造函数都将对象的每一个成员初始化。但是,别混淆赋值(assignment)和初始化(initiation)。

class ABEntry{

public:

ABEntry(const std::string &name, const std::list<PhoneNuber> &phones );

private:

    std::string theName;

    std::list<PhoneNuber> thePhones;

    int numTimesConsulted;

}

ABEntry(const std::string &name, const std::list<PhoneNuber> &phones ){              //这些都是赋值

theName = name;

thePhones = phones;

numTimesConsulted = 0;

}

ABEntry(const std::string &name, const std::list<PhoneNuber> &phones ): theName(name), thePhones(phones), numTimesConsulted(0)

{               //这些都是初始化

}

示例3-4-1 赋值与初始化

C++规定,对象的成员变量的初始化动作发生在进入构造函数本体之前。成员初始化列(memberinitialization list)比赋值效率高,但是内置类型的效率是一样的。

一旦你已经很小心将“内置型成员变量”明确地加以初始化,而且也确保你的构造函数运用“成员初始列”初始化base class和成员 变量,那就只剩下“不同编译单元内定义之non-conststatic对象”的初始化次序。

所谓static对象,其寿命从被构造出来直到程序结束为止。这种对象包括global对象,定义于namespace作用域内的对象,在class内,在函数内,以及在文件作用域内被声明static的对象。

函数内的static对象称为local static对象,其他称为non-local static对象。

所谓编译单元(translationunit)是指产出单一目标文件(single object file)的那些源码。

C++对定义于不同编译单元内的non-local static对象的初始化次序没有明确定义。

可以解决该问题的方法:将每个non-localstatic对象搬到自己的专属函数内(该对象在此函数声明为static)。这些函数返回一个reference指向它所包含的对象。然后,用户调用这些函数,而不直接涉及这些对象。

C++保证:函数内的local static对象会在“该函数被调用期间”“首次遇上该对象之定义式”时被初始化。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息