文章目录
  1. 1. 让自己习惯C++
    1. 1.1. 条款01:视C++为一个语言联邦
    2. 1.2. 条款02:尽量以const,enum,inline替换#define
    3. 1.3. 条款3:尽可能使用const
      1. 1.3.1. bitwise constness vs logical constness

让自己习惯C++

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

  • C++ 高效编程守则是状况而变化,取决于你使用C++的哪一个部分。

C++并不是一个单一范式编程语言,它同时支持过程形式(procedural),面向对象设计(object-oriented)、函数形式(functional)、泛型形式(generic),元编程形式(meta-programming)。

所以作者认为并不是每一个规则都是适用于所有的这些范式的,那么我们可以将C++语言分为一下几种次语言:

  • C
  • Object-Oriented C++
  • Template C++
  • STL

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

  • 对于单纯常量,最好以const对象或enums替换#define
  • 对于形似函数的宏(macros),最好改用inline函数替换#define

#define的缺点:

  1. define 定义的值无法被编译器和调试器看到,出问题了很麻烦。
  2. 没有良好的封装新,不能控制作用域。

const

使用const我可以这样声明一个常量:

1
2
const std::string ProductName("Mango Game");
const double Pi = 3.1415;

还可以声明一个类的专属常量:

1
2
3
4
5
6
7
8
9
//Header
class Game {
private:
static const int MaxGamePlayer ;
...
};

//cpp file
const int Game::MaxGamePlayer = 5;

enum hack

如果需要编译时使用到常量就需要enum hack这个技巧,实现如下:

1
2
3
4
5
class GamePlayer {
private:
enum { NumTurns = 5}
int scores[NumTruns];
};

inline function

有一些宏长得很像函数,这种宏有类型安全问题和不可预料行为两个问题。可以使用inline function来替代。

1
2
3
4
5
6
7
8
9
//这个MAX宏很不好,会出现奇怪的一些问题且无法调试
#define MAX(a,b) ((a) > (b) ? (a) : (b))

//Good
template<typename T>
inline T Max(const T& a, const T& b)
{
return (a > b ? a : b);
}

条款3:尽可能使用const

  • 将某些东西声明为const可帮助编译器侦测出错误用法。const可被施加于任何作用域内的对象、函数参数、函数返回类型、成员函数本体。
  • 编译器强制实施bitwise constness,但你编写程序时应该使用“概念上的常量性”(conceptual constness)。
  • 当const和non-const成员函数有着实质等价的实现时,令non-const版本调用const版本可避免代码重复。

const提供一种语义上的约束,它能够约束变量使用者的行为。当它作用于针、智能指针、迭代器上的时候可以指向指针本身也可以是指针指向物。作者提出了一个识别的技巧:如果关键字const出现在星号左边,表示被指物是常量;如果出现在星号右边,表示指针本身是常量。

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

char greeting[] = "Hello"
char *p = greeting; //non const point, const data
const char * p = greeting; //non const point, const data
char const * p = greeting; //non const point, const data
char * const p = greeting; //const point, non const data
const char* const p = greeting; //const point, const data

const std::vector<int>::iterator it; // --> T * const p
*it = 10; //合法
it++; //不合法
std::vector<int>::const_iterator it; // --> const T * p
it = 10; //不合法
it++; //合法

std::shared<T> p1;
std::shared<const T> p; // --> const T *p
p = p1; //合法
*p.get() = x; //不合法
const std::shared<T> p; // --> T* const p
p = p1; //不合法
*p.get() = x; //合法

有点头晕,我有一个不是很恰当地记忆方法。可以把const看成修饰它右边所有内容的,以const char* p为例,把p看成一个指针,而*p则是数据,所以const是修饰数据的。而char * const p中,const右边只有p,所以它只是限制指针本身的。

bitwise constness vs logical constness

当限制一个成员函数为const,编译器会执行bitwise constness,即检查函数内部是否修改了类的成员变量。但是写代码的时候应该注意逻辑上的常量限制,比如说一个你返回了一个指向内部变量的指针,这个函数虽然符合编译器的const限制但却不是很好的一个写法。

[to be continued]

文章目录
  1. 1. 让自己习惯C++
    1. 1.1. 条款01:视C++为一个语言联邦
    2. 1.2. 条款02:尽量以const,enum,inline替换#define
    3. 1.3. 条款3:尽可能使用const
      1. 1.3.1. bitwise constness vs logical constness