读书笔记 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.1415926535C++: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;
}
这种方法在单线程中没有什么问题,但是多线程就需要做单件模式了
相关文章推荐
- 《Effective C++》 读书笔记(一) 让自己习惯C++
- Effective C++ 读书笔记(一)让自己习惯C++
- 《Effective C++》第1章 让自己习惯C++-读书笔记
- 【读书笔记】Effective C++-1 让自己习惯C++(之三)
- 【读书笔记】Effective C++-1 让自己习惯C++(之二)
- 【Effective C++】条款01-让自己习惯c++
- 《Effective C++ 3》01 让自己习惯C++ 条款:01-04
- 【读书笔记】Effective C++-1 让自己习惯C++(之一)
- 《Effective C++》1-让自己习惯C++
- Effective c++ 第一章 让自己习惯C++
- Effective C++ -- 让自己习惯C++
- Effective C++(一)让自己习惯C++
- effective C++阅读笔记一——让自己习惯C++
- effective c++之让自己习惯C++
- Effective C++(一)让自己习惯C++
- Effective C++第一章:让自己习惯C++
- Effective C++ 笔记一 让自己习惯C++
- Effective C++ 1.让自己习惯C++
- 【Effective C++】让自己习惯C++
- 《Effective C++》让自己习惯C++:条款1-条款4