Effective C++ (01)
来源:互联网 发布:网络打印机显示错误 编辑:程序博客网 时间:2024/05/22 12:03
条款1:
C++:
c、面向对象的c++、带模版的c++、STL
条款2:尽量以const、enum、inline代替#define
宁可以编译器替换预处理器。#define没有进入符号表,造成无法跟踪。
常量指针。
以const代替#define的所谓常量定义功能
以inline代替#define的所谓宏定义功能
class内部的专属常量。为了将常量的作用域限制于class内,必须让其成为一个类的成员,为了确保这个常量只有一份,必须声明为static。
const int GamePlayer::m_nNumTurns;Class GamePlayer{ Static const int m_nNumTurns = 5; Int scores[m_nNumTurns];}; const int GamePlayer::m_nNumTurns;
C++通常需要一个定义式,然而如果是class专属常量又是static且为整数类型(int、char、bool),则需要特殊处理。只要不取它们的地址,可以声明并使用它们而无需提供定义式。但如果要取class常量的地址,就必须提供一个定义式:
要放入实现文件而非头文件,由于在声明时已经获得初值,因此定义时不可以在设初值。
声明是原形,定义时具体实现。。。
enum hack:
一个枚举类型的数值可以充当int被使用。
Class GamePlayer{ enum{m_nNumTurns = 5}; Intscores[m_nNumTurns];};
取一个enum的地址不合法,取一个#define也不合法。
如果不想让别人获得一个pointer或reference,enum可以实现。
宏定义:副作用。
用template inline代替宏定义。
条款3:尽可能使用const
const出现在*的左边,表示被指物是常量;如果出现在*右边,表示指针本身是常量;如果出现在*两边,则两者都是常量。
const int widget = 1;
int const widget = 1;
STL的迭代器是以指针为基础的,迭代器的作用类似于T*指针。声明iterator为const就像声明指针为const一样(T* const)。表示这个迭代器不能指向其他不同的东西,但它指向的东西的值是可以变的。
如果希望它所指向的值是不能改变的,需要const_iterator(const T*)
std::vector<int> vec;const std::vector<int>::iterator iter= vec.begin();*itr = 10; //没有问题++itr; //错误!常量指针不能再指向其他的地方std::vector<int>::const_iterator itr= vec.begin();*itr = 10; // 错误!++itr; //没有问题函数返回值为const:
有理数的operator*声明
class Rational {…};
const Rational operator* (constRational& lhs, const Rational& rhs);
可以避免下述操作:
Rational a,b,c;
(a*b) = c;
在operator*的结果上再调用operator=。
例如if (a * b = c) // 可能是==
如果是内置类型,直接不合法。因此一个设计良好的用户自定义类型,需要与内置类型无缝对接好。
参数为const:
除非要对参数进行修改并返回,否则尽量声明为const
const成员函数
目的:为了确认该成员函数能够作用于const对象上面。
1:使class接口比较容易被理解。得知哪个函数可以改动对象而哪个不行,加了const的函数一目了然。
2:使操作const对象成为可能。这对高效编程很有效。改善c++性能的一个方法是由传值调用改为传引用,而前提是有const成员函数可以用来处理const对象。
问题:非const成员函数不能处理const对象???
如果成员两个函数的const性质不同,则可以被重载!
Class TextBlock
{ Const char& operator[](std::size_t position) const // const对象的{ Ruturn text[position];}Char& operator[](std::size_t position) // 非const对象的{ Return text[position];}Private: Std::string text;}; Textblock tb(“Hello”);Cout << tb[0]; // 调用非const对象的Const TextBlock ctb(“World”);Cout << ctb[0]; // 调用const对象的真实中:const对象大多用于函数调用的传递结果。
例如:
Void Print(const TextBlock& cbt){ Cout << ctb[0];}
只要重载,给予不同版本不同的返回值。
如何在const成员函数内部修改成员数据的值?mutable。
Class TextBlock{Const char& operator[](std::size_t position) const // const对象的{ Length = XXX; Ruturn text[position];}Char& operator[](std::size_t position) // 非const对象的{ Return text[position];}Private:Std::string text;Mutable int length;};
如果const和非const的代码有大量重复,则可以用非const的代码调用const的代码
Class TextBlock{Const char& operator[](std::size_t position) const // const对象的{ Ruturn text[position];}Char& operator[](std::size_t position) // 非const对象的{ // 先将非const对象将其转化为const类型,const返回const char&类型,再将其去掉const性质,转化为char&类型、 // 如果不转化为const对象,则会调用自己,无限循环。。。 Return const_cast<char&> (static_cast<const TextBlock&>(*this) [position]);}Private:Std::string text;};
条款4:确定对象在使用前已被初始化
int x;
int arr[10];
数组不保证被初始化,内容是随机的
int arr[10] = {0};
当x是成员函数时,不保证被初始化为0.初始化是程序员的事。
初始化与赋值的区别。类内的成员对象的初始化在初始化列表中完成,即在程序员提供的显式构造函数之前,在程序员提供的显式代码里,被初始化后的内置对象将执行operator=(赋值)操作。
对于类内的内置数据类型(int、char),编译器在成员初始化列表内不管它们,由程序员负责。
当想让初始化列表调用对象的默认构造函数时,可以:theObj()。编译器会自动给你调用对象的默认构造函数。但是尽量将所有的成员都在初始化列表中出现!以避免遗漏内置类型
如果是const、reference则必须在初始化列表中初始化!因为const、reference只能被初始化一次,如果没有在初始化列表中提供,则编译器会默认给其初始化,而程序员则不能再显式的更改它们!
初始化次序:父类(按照继承顺序)、成员对象(按照声明顺序)。即使在初始化列表中顺序被打乱,也无影响。
所谓static对象,其寿命从被构造出来直到程序结束为止,因此stack和heap-based对象都被排除。
static的对象:定义于global的、定义于namespace的、在classes内的对象,这些对象没有static关键字。在函数内、在file作用域内声明为static的对象。在函数内声明为static的对象为局部对象,其他的都是non-local static。它们的析构函数在main结束后自动调用。
函数内的static对象称为local static对象(因为它们对函数而言是local)
non-local static:定义于global的、定义于namespace的、在classes内的对象、file作用域内声明的static对象
如果一个非局部的static对象的初始化用到了另一个编译单元的某个非局部的static对象,而这个对象可能尚未被初始化!对于多个目标文件(编译单元)的非局部static的初始化次序没有定义。
class FileSystem{pubic: size_tnumDisk() const;};extern FileSystem tfs; class directory {pubic: Directory(params);};Directory::Directory(params){ size_tdisks = tfs.numDisks();}
假设创建一个Directory对象:
Directory tempDir(params);
这里需要保证tfs在tempDir之前被初始化。但是它们定义于不同编译单元的非局部static对象。如何能保证tfs在tempDir之前先被初始化?
无法决定它们的初始化次序
extern : global对象
将每一个非局部static对象搬到自己的专属函数内(对象被声明为static),函数返回一个指向它的引用,类似于单例模式?
C++保证,局部static对象会在该函数被首次调用期间被初始化
class FileSystem{pubic: size_tnumDisk() const;};FileSystem& tfs(){ staticFileSystem fs; returnfs;} class directory {pubic: Directory(params);};Directory::Directory(params){ size_tdisks = tfs.numDisks();}Directory& tempDir(){static Directorytd;return td;}
多线程下带有不稳定性
记住:
为内置对象(int char bool)手工初始化
构造函数最好使用初始化列表
- Effective C++:条款01
- Effective.C 读书笔记01
- Effective C++(四)
- Effective C++(五)
- 《Effective C++》(一)
- 《Effective C++》(二)
- 《Effective C++》(三)
- 《Effective C++》(四)
- 《Effective C++》(五)
- 《Effective C++》(六)
- 《Effective C++》阅读笔记01
- 《Effective C++》笔记(一)
- 《Effective C++》笔记(一)
- Effective C++(中文版)下载
- Effective C++(三)资源管理
- Effective C++(五)实现
- 《Effective C++》读书笔记(二)
- 《Effective C++》读书笔记(三)
- python格式化dict输出
- DirectX 性能优化
- Block编程值得注意的那些事儿
- ExtJs学习笔记 根据数据库生成动态多级树
- 不可见索引
- Effective C++ (01)
- 复杂的心情
- 函数索引
- hibernate中一对多等关系映射图和主键生成策略
- 【HTML】使用Iframe标签显示目标网页(内容)的某区域
- 购物车3种实现方式
- 递归-汉诺塔
- gerrit.config sample
- Objective-C语言学习之数据类型