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

读书笔记 Effective C++: 01 让自己习惯C++

2013-03-14 23:20 726 查看

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

C++主要有4个次语言:

1. C。内置数据类型,数组,指针。

2. Object-Oriented C++。封装,继承,多态。

3. Template C++。泛型编程,模板元编程。

4. STL。容器,迭代器,算法,仿函数。

各个次语言都有自己的规约。

条款02:尽量使用const,enum,inline替换#define

1. 常量

  C: #define PI 3.1415926535

  C++:const double PI = 3.1415926535;

  相比#define而言,const double具有更小的obj文件。因为const变量放在记号表内,而#define会盲目的替换所有宏而出现多份3.1415926535。

  C:const char* const name = "LeaGem";

  C++:const std::string name("LeaGem");

  很多时候,std::string都可以取代char*

2. 类内的常量

  方式1:

  class GamePlayer{

  private:

    static const size_t Num = 10;

    int scores[Num];

  };

  由于Num是数组长度,编译器可能不允许在类外面定义Num的值。

  新的编译器可以采用方式1,在类内定义整形的值;

  旧的编译器可以采用方式2,使用enum hack实现;

  方式2:

  class GamePlayer{

  private:

    enum { Num = 10 };

    int scores[Num];

  };

3. 函数

  C: #define MAX(a, b) f((a)>(b)?(a):(b))

  C++:

  template<typename T>

  inline void max(const T& a, const T& b)

  {

    f(a>b?a:b);

  }

  使用宏定义的函数:1. 阅读性不好; 2. 采用MAX(++a, b)调用的时候,a可能被累加2次

条款03:尽可能使用const

1. 指针和迭代器

  const char* 与char const * 等价,每个人有每个人的习惯,主要是阅读别人的代码能看懂;

  const std::vector<int>::iterator iter;

  *iter = 10; //正确

  iter++; //错误

  std::vector<int>::const_iterator cIter;

  *iter = 10; //错误

  iter++; //正确

  从形似上看,与char*恰好相反。前者const作用于迭代器,相当于char* const; 后者const作用于对象,与const char*类似。

2. 重载操作符函数的返回值

  template<typename T>

  const T operator*(const T&, const T&);

  返回值要添加const,是为了防止别人调用: (a*b)=c;

  这种调用虽然没有什么意义,但是可能是“想要==却意外写成=”了,可以在编译阶段发现此类错误;

3. const成员函数

  const成员函数只能被const对象调用。一般来说,程序员并不会主动定义const对象,const对象主要出现在函数参数的reference-to-const上。

  class Text{

  public:

     void f() const;

     void g();

  };

  void print(const Text& text)

  {

    text.f();   //正确

    text.g();  //错误

  }

  bitwise constness

class GamePlayer
{
public:
GamePlayer(const std::string& name)
  : name_(name)
{
}
const void capitalizeFirstLetter( ) const
{
  char* p = const_cast<char*>(name_.c_str( ));
  *p = std::toupper(*p);
}
const std::string& getName( ) const
{
  return name_;
}
private:
  std::string name_;
};

这个例子举出了const函数也可以改变对象内的某些值(可以通过g++ 4.6.3编译,但并不是所有的编译器都可以如此),但是优雅的程序也不应该这么做。

如果某些情况下,需要使用一些变量来标记const函数的状态值,可以使用logical constness。

  logical constness

  const 成员函数也可能需要改变类对象中的一些变量的值,这些变量包括表示对象状态的值。

  关键字mutable正是用来释放non-static成员变量的bitwise constness约束的。

class GamePlayer
{
public:
  GamePlayer(const std::string& name)
    : name_(name)
  {
  }
  const void rename(std::string rename ) const
  {
    name_.assign(rename);
  }
  const std::string& getName( ) const
  {
    return name_;
  }
private:
  mutable std::string name_;
};

  const和non-const成员函数要避免重复

class GamePlayer
{
public:
  GamePlayer(const std::string& name)
    : name_(name)
  {
  }

  std::string& getName( )
  {
    return const_cast<std::string&>(static_cast<const GamePlayer&>(*this).getName( ));
  }
  const std::string& getName( ) const
  {
    return name_;
  }
private:
  mutable std::string name_;
};

  1. 用static_cast给*this加上const

  2. 用const_cast给返回值去掉const

  3. 反向做法“const函数调用non-const”是不优雅的,因为const成员函数承诺不修改对象的值,而non-const成员函数却没有承诺。

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

1. 构造函数对成员变量的初始化

  初始化的顺序是由类中定义各个成员的顺序,而不是构造函数指定的顺序;

2. global或者namespace作用域变量的初始化

  全局变量可能会被其他文件extern,ertern该变量被调用的时候,有可能该对象尚未初始化,因为C++对“定义于不同编译单元内的non-local static对象”的初始化顺序并无明确的定义。

  解决的办法是,把non-local static对象定义在全局函数里面。

  Text& gettest(){

    static Text text;

    return text;

  }

  这种方法在单线程中没有什么问题,但是多线程就需要做单件模式了  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: