目录
条款01
内置类型,值传递比引用传递更高效。 用户自定义类型,因为存在构造函数和析构函数,使用pass-by-reference-const
会更好,尤其是使用模板时。
条款02
尽量以cosnt
,enum
, inline
,替换#define
class
的专有常量,一般将常量的作用域限制于 class
中,此时它应该为一个成员变量,为了确保其只有一份实体,应该将其设为静态变量。
const
与 enum
在定义常量时取代 #define
inline
在定义 类函数宏 时取代 #define
,并且inline
会有类型安全检查,符合 C++
严格类型匹配的风格 在使用 inline
定义函数时,可以使用 template
来定义模板函数,这样就能够实现与 #define
相类似的可以用于不同类型的参数的函数。
class Game{
private:
static const int num = 5; // 声明常量
static const * const str = "Hello"; // 定义常量指针时应该即指向指针又指向内容
enum {num2 = 5}; // 使用枚举定义常量
int score[num]; // 使用常量
};
其中static const
只是常量声明,没有进行常量定义,应在Game的实现代码中添加
const int Game::num; // num常量的定义
条款03
const
作用:
-
修饰全局变量或常量
-
修饰文件、函数或块中被声明为
static
的对象在函数声明中,
const
可与函数返回值,函数参数,函数自身(若是成员函数)相结合返回
const
变量,可降低意外,同时保持了安全性和高效性。const
修饰成员函数,一是为了让该成员函数能够作用于
const
对象上二是使
class
接口容易理解,不容易出错。 -
修饰类内部的
static
和non-static
成员变量 -
修饰指针(双
const
),引用,关键
指针与迭代器:
std::vector<int> vec;
const std::vector<int>::iterator iter = vec.begin(); // 相当于int *const
*iter = 10; // correct
iter++; // error
std::vector<int>::const_iterator citer = vec.begin(); // 相当于const int *
*citer = 10; // error
iter++; // correct
很多函数需要有const
与non-const
版本,但实现时会出现大量的代码重复,此时
class TextB {
public:
...
const char& operator[](std::size_t position) const {
... // 边界检验
... // 标志访问信息
... // 检验数据完整性
return text[position];
}
char& operator[](std::size_t position) {
return const_cast<char &>(
static_cast<const TextB&>(*this)[position]
); // 进行了两次强制类型转换,第一次将non-const转换为const并取出其中的值,第二次将取出的值去掉const属性
}
};
条款04
使用变量之前一定要进行初始化。
内置对象要进行手工初始化,而自定义类型的构造函数最好使用初始化列表,而不要在构造函数中使用赋值操作。
要使用成员变量初始化列表进行初始化,这样效率更高,若采用赋值的方式首先要调用默认构造函数赋初值,然后再一一进行赋值操作。此时默认构造函数赋初值这一步被浪费了。
若成员变量为const
或references
,则一定得使用初始化列表进行初始化,因为他们肯定需要初值,只能被初始化,而不能被赋值。
成员初始化顺序,基类-->子类的声明次序
但是C++对定义在不同编译单元内的非局部静态对象的初始化相对次序并无明确的定义,所以需要一个简单的设计来解决该问题,为每个非局部静态对象设计一个专属函数(该对象在函数内部被设计为static
),这些函数返回一个reference
来指向它所包含的对象,然后用户调用这些函数,并不直接使用这些对象。
即将非静态局部对象转化为局部的静态对象,这样能够保证其在何时进行初始化。类似与设计模式中的Singleton
// 线程安全的懒汉式加锁实现
// 使用instance方法返回一个单例对象
class Singleton1 {
protected:
Singleton1() {
pthread_mutex_init(&mutex);
}
private:
static Singleton1 *p;
public:
static pthread_mutex_t mutex;
static Singleton1* instance();
};
pthread_mutex_t Singleton1::mutex;
Singleton1 Singleton1::p = NULL;
Singleton1* Singleton1::instance() {
if (p == NULL) {
// 1
pthread_mutex_lock(&mutex);
if (p == NULL) // 此处的判断语句的作用:
// 当线程A和B同时进入单例对象中,并且同时执行了第一次判断进入了加锁函数,此时假设A上锁了,B并没有获得资源,于是在1处等待,等到A创建完对象之后,B获得资源,此时A已经创建了对象,此时p已经不为空,所以必须要再次判断,否则这种情况下可能会创建多个实例,与单例模式的定义不符
p = new Singleton1();
pthread_mutex_unlock(&mutex);
}
return p;
}
// 线程安全的懒汉式内部静态变量实现
class Singleton2 {
protected:
Singleton2() {
pthread_mutex_init(&mutex);
}
private:
static pthread_mutex_t mutex;
static Singleton2* instance();
};
pthread_mutex_t Singleton2::mutex;
Singleton2* Singleton2::instance() {
pthread_mutex_lock(&mutex);
static Singleton2 obj; // 可以保证拥有静态实例,因为静态变量只会创建一次
pthread_mutex_unlock(&mutex);
return &obj;
}