让自己习惯C++

tangjikede 2018-07-21

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

View C++ as a federation of languages


如今的C++是个多重范型编程语言(multiparadigm programming language),它支持如下形式:

  • procedual(过程形式)
  • object-oriented(面向对象形式)
  • functional (函数形式)
  • generic(泛型形式)
  • metaprogramming(元编程形式)

最简单的办法是把它看作一个由相关次语言组成的联邦:

  • C:即C语言,其实C++不过是较高级的C解法,它主要有:
  • blocks(区块)
  • statements(语句)
  • preprocessor(预处理器)
  • built-in data types(内置类型)
  • arrays(数组)
  • pointers(指针)
  • Object-Oriented C++:面向对象设计
  • classes(构造与析构函数)
  • encapsulation(封装)
  • inheritance(继承)
  • polymorphism(多态)
  • dynamic binding(动态绑定—即virtual函数)
  • Template C++:这是C++泛型编程(generic programming)的部分,templates带来了TMP(templates metaprogramming—即模板元编程)
  • STL:本质就是个template程序库,它对容器、迭代器、算法以及函数对象的规约有极佳的紧密配合与协调

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

Prefer consts,enums,and inlines to #defines


宁肯以编译器替换预处理器!因为#define不被看作语言的一部分

当你做出如下定义:

#define ASPECT_RATIO 1.653

  • 1

它在编译器开始处理源码之前就被预处理器移走,编译器不会看到它,所以它也不存在于记号表(symbol table)中。当你使用这个常量报错时会发现,错误信息也许会提到1.653而非ASPECT_RATIO,你将因为追踪它而浪费时间。

解决办法就是以常量替换宏定义:

const double AspectRatio = 1.653

  • 1

它的另外一个优点是缩短代码长度,因为预处理器会盲目的将ASPECT_RATIO替换为1.653导致出现多份1.653。

两种特殊情况

  • 常量指针:要想在头文件定义一个常量字符串必须写两次const
  • const char* const authorName = "Scout Meyers"; //char*也可用string替换
  • class专属常量:如果想将一个常量作用域限制在一个类中,你必须让这个常量成为类的一个 member(成员),而且为了让这个类内常量至多只有一份实体,还必须让它成一个 static成员
  • class GamePlayer {
  • private:
  • static const int NumTurns = 5; //常量声明式
  • int scores[NumTurns]; //使用该常量
  • ......
  • };

声明和定义:声明和定义是完全同的概念,声明是告诉编译器“这个函数或者变量可以在哪找到,它的模样像什么”。而定义则是告诉编译器,“在这里建立变量或函数”,并且为它们分配内存空间。

一般C++要求你给你使用的任何东西提供一个定义式,除非它是class专属常量&&static类型&&整数类型(ints、chars、bools),只要不取地址就无须写定义式。

非要看定义式的话、给你

const int GamePlayer::NumTurns;

  • 1

需要注意!这个式子要放在实现文件而非头文件,原因往上瞅瞅。

其实这就是“in-class”初值设定(在编译期间需要一个class常量值,只针对整数常量):声明时设定初值,定义时不再设。当然如果不是整数类型的话也可以定义时再设初值。

enum hack补偿法

如果恰巧编译器秀逗了,你还可以使用枚举法设定初值:

class GamePlayer{

private:

enum { NumTurns = 5 };

int scores[NumTurns];

......

};

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

enum还有以下优点:

  • enum hack 行为比较像 #define 而非 const ,取const地址是合法的,而取enum和#define地址通常是不合法的,enum 和 #define 一样绝不会导致非必要的内存浪费
  • 它是(TMP)模板元编程的基础

inline

一个常见的#define误用情况是去实现宏(macros),宏看起来像函数,但它不会招致函数调用带来的额外开销。

来看一个简单的宏:

// 以a和b的较大值调用f

#define CALL_WITH_MAX(a,b) f( (a) > (b) ? (a) : (b) )

  • 1
  • 2

宏有两个特点

  1. 无论何时,都要记得给宏中的所有参数加上小括号

用inline函数代替

template<typename T>

inline void callWithMax( const T& a, const T& b){

f( a > b ? a : b );

}

  • 1
  • 2
  • 3
  • 4

此外由于它是一个真正的函数,它遵守scope(作用域)的概念和访问规则,因此,完全可以封装在类内,这是宏无法做到的。

让自己习惯C++

相关推荐