码迷,mamicode.com
首页 > 编程语言 > 详细

Effective C++: 01让自己习惯C++

时间:2017-09-22 10:19:43      阅读:178      评论:0      收藏:0      [点我收藏+]

标签:ctr   编译   ural   files   error   调试   fine   改变   额外   

01:视C++为一个语言联邦

         1:今天的C++已经是个多重范型编程语言(multiparadigm programming language),一个同时支持过程形式(procedural)、面向对象形式(object-oriented)、函数形式(functional)、泛型形式(generic)、元编程形式(metaprogramming )的语言。所以,需要将C++视为一个由相关语言组成的联邦而非单一语言。

         2:这个联邦中主要包含4个次语言:C、Object-Oriented C++(classes,封装,继承,多态等)、Template C++(泛型编程)、STL(template标准库)。

         3:当你从某个次语言切换到另一个,导致高效编程守则要求你改变策略时,不要感到惊讶。

 

02:尽量以const, enum, inline替换#define

         1:该条款的本质是:以编译器替换预处理器。

         2:#define ASPECT_RATIO 1.653这样的宏定义,ASPECT_RATIO也许从未被编译器看见,因而也就没有记录到符号表中,所以调试器也有可能不认识它。可以使用下面的语句代替它:

const double AspectRatio = 1.653; 至少AspectRatio 肯定会被编译器看见,从而进入符号表。

         3:一个属于枚举类型的数值可以充当ints被使用,比如一个枚举值就可以作为数组大小的定义:

class GamePlayer {
private:
  enum { NumTurns = 5 };

  int scores[NumTurns];              // fine
  ...
};

 

         4:使用#define定义一个看起来像函数一样的宏,虽然它不会招致函数调用带来的额外开销,但是却也不会有必要的语法检查,因此必须记住为宏中的所有实参加上小括号。此时,可以使用inline函数,inline函数具有宏一样的效率,还具有一般函数的所有可预料行为和类型安全性。

 

03:尽可能使用const

         1:如果关键字const出现在星号左边,表示被指物是常量;如果出现在星号右边,表示指针自身是常量;如果出现在星号两边,表示被指物和指针两者都是常量。const写在类型之前,或者写在类型之后,星号之前,这两种写法的意义是相同的。

         2:声明迭代器为const就像声明指针为const一样(即声明一个T* const指针),表示这个迭代器不得指向不同的东西,但它所指的东西的值是可以改动的。如果你希望迭代器所指的东西不可被改动(即希望STL模拟一个const  T*指针),你需要的是const_iterator:

std::vector<int> vec;
...
// iter acts like a T* const
const std::vector<int>::iterator iter = vec.begin();
*iter = 10;                                 // OK, changes what iter points to
++iter;                                     // error! iter is const

// cIter acts like a const T*
std::vector<int>::const_iterator cIter = vec.begin();
*cIter = 10;                                // error! *cIter is const
++cIter;                                    // fine, changes cIter

 

        

3:让函数返回一个常量值,往往可以降低因客户错误而造成的意外,而又不至于放弃安全性和高效性。比如:

class Rational {
public:
    Rational(int numerator = 0,int denominator = 1):numerator(numerator), denominator(denominator){};
    int getnumerator() const {return numerator;}; 
    int getdenominator() const {return denominator;};

private:
  int numerator;
  int denominator;
};

const Rational operator*(const Rational& lhs, const Rational& rhs)
{
    return Rational(lhs.getnumerator() * rhs.getnumerator(),
                  lhs.getdenominator() * rhs.getdenominator());
}

 

         让operator*返回一个const对象,就可以防止下面错误的发生(程序员的原意可能是a*b == c):

    Rational a, b, c;
    ...
    a * b = c;

 

        

4:如果成员函数是const的,则该成员函数才可作用于const对象。

如果两个成员函数如果只是常量性(一个是const,一个非const)不同,则这是一种重载。

 

04:确定对象被使用前已先被初始化

         1:永远在使用对象之前先将它初始化,对于内置类型,必须手工完成此事。

         2:在构造函数中,尽量使用成员初始化列表初始化所有成员。这样做有时候绝对必要(比如具有const或reference的类),而且往往比赋值更高效。

         3:不同编译单元内定义的non-local static对象的初始化次序是未定的。所谓non-local static对象,是指定义在函数之外的static对象。

如果某编译单元内的某个non-local static对象的初始化动作使用了另一编译单元内的某个non-local static对象,它所用到的这个对象可能尚未被初始化,因为C++对“定义于不同编译单元内的non-local static对象”的初始化次序并无明确定义。

编译单元A内,有如下的定义:

class FileSystem {
public:
  ...
  std::size_t numDisks() const;
  ...
};

extern FileSystem tfs; 

 

而编译单元B内有下面的定义:

class Directory {                       // created by library client
public:
   Directory( params );
  ...
};

Directory::Directory( params )
{
  ...
  std::size_t disks = tfs.numDisks();   // use the tfs object
  ...
}

Directory tempDir( params );            // directory for temporary files

 

现在,除非tfs在tempDir之前初始化,否则tempDir的构造函数会用到尚未初始化的tfs。

幸运的是一个小小的设计便可完全消除这个问题。唯一需要做的是:将每个non-local static对象搬到自己的专属函数内(该对象在此函数内被声明为statIc)。这些函数返回一个reference指向它所含的对象。然后用户调用这些函数,而不直接指涉这些对象。换句话说,non-local static对象被local static对象替换了。

这个手法的基础在于:C++保证,函数内的local state对象会在“该函数被调用期间,首次遇上该对象之定义式”时被初始化。

所以,上面的例子可以改成:

class FileSystem { ... };          

FileSystem& tfs()
{
  static FileSystem fs;
  return fs;
}

class Directory { ... };

Directory::Directory( params )
{
  ...
  std::size_t disks = tfs().numDisks();
  ...
}

Directory& tempDir()
{
  static Directory td;
  return td;
}

 

这么修改之后,这个系统程序的客户完全像以前一样地用它,唯一不同的是他们现在使用tfs ()和tempDir()而不再是tfs和tempDir。也就是说他们使用函数返回的“指向static对象”的references,而不再使用static对象自身。

Effective C++: 01让自己习惯C++

标签:ctr   编译   ural   files   error   调试   fine   改变   额外   

原文地址:http://www.cnblogs.com/gqtcgq/p/7572804.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!