C++-Effective C++ Items
Item2:尽量以const,enum,inline替换#define
原因:1, #define ASPECT_RATIO 1.63
编译错误时产生魔数,应以const double Aspect_Ratio = 1.63替换
2, #define不能提供作用域,如某个类的常量
class GamePlayer{
private:
static const int = 1024;
int scores[NumTruns];
};
上面的类也可以通过下面的enum实现, 但是此种实现更像是define,因为取NumTruns的地址在此种情况下不合法,define的标识符也不能取地址。
class GamePlayer{
private:
enum{ NumTruns = 5 };
int scores[NumTruns];
};
3, 用inline替换define的函数
#define CALL_WITH_MAX(a,b) f((a) > (b) ? (a) : (b))
应以如下inline函数替换
template <typename T>
inline void CallWithMax(const T &a, const T &b)
{
f(a > b ? a : b);
}
如果不, 会怎么样:
N.A
Item 3: 尽量使用const
原因:1, 使用const修饰返回值可以降低客户错误造成的意外
const Rational operator* (const Rational &lhs, const Rational &rhs);
可以防止:
Rational a, b, c;
(a * b) = c;
2, const 成员函数的作用是1)确认函数可以作用域const对象。2)操作const对象,pass by reference to const是C++程序的关键,必须有const函数
关于第二点要说明的是1)const对象调用成员函数,必须为const成员函数,原因见http://www.cnblogs.com/dracohan/archive/2009/11/30/1614089.html
2)非const对象优先调用非const成员函数,如果无const成员函数,也可以调用该函数对应的const重载函数。
3)const成员函数和非const成员函数重载,可让非const成员函数调用const成员函数,因为const函数要求更严格。
3,关于什么函数可以为const,const成员函数可以修改它所处理的对象内的bits,但只有在客户端检测不出的情况下才可以。
Item 4: 类成员的初始化
原因:
为保证所有的类成员都被初始化,可以将所有的变量放入初始化队列。
如果不, 会怎么样:
如果遗漏,则有些变量没有被初始化,会导致不明确行为。
Item5: 1)一个空类,编译器会默默的编写4个函数:默认构造函数,析构函数,copy构造函数,copy赋值操作符
Empty& operator= (const Empty& rhs){...}
2) class定义内有reference或者const成员的,编译器拒绝生成copy赋值操作符,因为它也不知道怎么办
3) 基类的copy 赋值操作符如果是私有的,则编译器不会为派生类生成copy赋值操作符
Item6:可以通过两种方式防止拷贝动作:
1)将copy构造和copy赋值操作符声明为private,但此种方法不能防止member函数或者friend函数这么做。
2)可以将copy构造和copy赋值操作符声明为private,并单独生成一个基类。想要此功能的类,私有派生自此基类。此方法的原理是,编译器为派生类生成的默认copy构造和copy赋值操作符都尝试调用基类的对应兄弟,因为是private,必定失败,因为编译器会拒绝。
class Uncopyable{
protected: //允许derive对象构造和析构
Uncopyable(){}
~Uncopyable(){}
private: //不允许copy
Uncopyable(const Uncopyable&);
Uncopyable& operator= (const Uncopyable& rhs);
}; class XXX : private Uncopyable{
...
};
Item 7: 1) 为多态的基类声明virtual的析构函数,否则派生类的部分得不到析构
2)如果不是多态的基类,不要声明virtual析构函数,影响性能。
3)不带virtual析构函数的类,不能被用作基类。
Item9: 绝不在析构函数和构造函数中调用virtual函数
原因: 1)因为构造和析构过程中,virtual函数不能下放到派生类中。如果下放,派生类中的变量尚未初始化,将导致未定义行为。
2) 有一个替代方法,就是让派生类调用基类的版本,但是在调用过程中传递一个派生类的信息给基类,从而加以弥补。
class Base{
public:
Base();
Log();
}; class Derived{
public:
Derived();
}; Base::Log(const LogInfo& Linfo)
{
cout << Linfo << endl;
} Base::Base()
{
Log(baseLogInfo);
} Derived::Derived()
{
Log(DerivedLogInfo);
}
如果不, 会怎么样:
实际调用的虚函数是基类中的版本,不是你想要的。
Item 10: operator= 返回一个reference to *this
原因: 随大流,主要为了实现连锁赋值,如a = b = c;
如果不,会怎么样: 无大碍
Item11: 在写赋值操作符的时候要注意自我赋值的情况
原因:如果不处理,则会导致异常,如下面的写法:
widget& operator= (const widget& rhs)
{
delete m_pointer;
m_pointer = new widget(*rhs.m_pointer);
return *this;
}
如果是同一对象,第一步就会删除指针,第二步读取异常。有两种方法可以避免问题:
1)合理安排语句的顺序:
widget& operator= (const widget& rhs)
{
widget* pb = m_pointer;
m_pointer = new widget(*rhs.m_pointer);
delete pb;
return *this;
}
2) 使用copy-and-swap技术
widget& operator= (const widget& rhs)
{
widget tmp(rhs);
swap(tmp);
return *this;
}
Item12: 如果你自己写了copy构造或者copy赋值函数,那么你就要小心了。
1)如果增加了成员变量,必须修改copy构造函数和copy赋值函数
2)如果是派生类,那么记得要调用基类的copy构造函数和copy赋值函数
如果不,会怎么样:
新增加的成员变量或者基类的成员变量将被默认构造函数初始化,不是要copy的值。
Item13: 以对象管理资源:
1)autoptr,auto_ptr<Pointee>(createPointee()); //createPointee is a factory function
2) shareptr, shared_ptr<Pointee>(createPointee());
3)注意不要在数组身上使用auto_ptr或者share_ptr,因为他们都是执行的delete操作而不是delete[]。
4)尽量不让工厂类函数直接返回为加工的指针。
5)copy动作对于auto_ptr来说是交出所有权,赋值后rhs为NULL。对于share_ptr来说是,是增加引用计数。
如果不,会怎么样:
N.A
Item14: 不是所有的对象都是在堆上被创建的,不一定都是new/delete,所以有时候需要自己写资源管理类,构造和析构函数有可能调用的是lock/unlock操作。
但是这种类需要注意的是这些类的copy,有几种方法处理copy:
1) 禁止copy,见Item6
2)对底层资源使用引用计数
3)做深拷贝,复制整块内存
4)交出拥有权,如auto_ptr
如果不,会怎么样:
会导致多个对象的指针指向同一块内存,当一个对象析构时,其资源已经被释放,其他对象析构将引起未定义行为。
Item15: 提供资源管理对象对底层资源的访问,同时适当提供隐式转换函数
class Font{
public:
operator Fonthandle() const {return f;}
private:
Fonthandle f;
};
Item16: 尽量以pass by const reference 代替pass by value
原因: 1) 可以提高效率,不用构造新的对象
2) 避免对象切割问题
如果不,会怎么样
N.A
Item30: inline函数不是随便用的
优点: 不用函数开销,比宏好用
缺点:1)增加代码大小。2)改变inline函数,客户需要重新编译。3)不能设置断点调试。
template放在头文件中,如果inline,则所有template生成出来的函数都将是inline的
Item31:将文件间的依存关系将之最低。
方法: 1)使用引用和pointer能办成的事,就不要用对象完成
2)以class声明式代替class定义式
3)为声明式和定义式提供不同的头文件。声明式文件中,要么是保存定义式的指针,并在接口中调用之;要么是声明一个基类的abstract类,实现类继承之。
Item34: 区分接口继承和实现继承
1)声明一个pure virtual函数的目的是为了让derived class只继承函数接口
2)声明一个普通virutal函数的目的是为了让derived class继承该函数的接口和默认实现
为了让这种默认继承更加安全,避免在派生类没有声明需要此函数的时候就使用了它的问题,可以用一个基类的pure virutal函数代替,并实现之。派生类实现此pure virtual 函数,从而成为concrete 类,并且调用基类名::函数名()来达到原来普通impure virtual函数的作用。
3)声明一个non-virtual函数的目的是为了给derived class一个接口和一份强制实现,不得修改。
Item36: 不重新定义继承而来的non-virtual函数
原因: Base* pb = new Derived;
如果不,会怎么样:通过基类或者派生类的指针调用该函数的时候会造成行为不一致。
Item37: 不重新定义继承来的缺省参数值
原因:缺省参数是编译器确定的,虚函数是运行时才确定的。
如果不,会怎么样: 会产生一个奇葩,派生类函数+基类的默认参数
Item39: private继承
private继承和普通继承有两个不同点:1)private继承而来的派生类不会自动将一个派生类对象转换为一个基类对象
2)private继承也叫实现继承,嘛意思呢,就是说基类的接口在派生类里毛都没了,全部封装
Item40: 多重继承
多重继承可用来公共继承几口,私有继承实现。
class CPerson: public IPerson, private PersonInfo{...};
C++-Effective C++ Items的更多相关文章
- 异常处理与MiniDump详解(2) 智能指针与C++异常
write by 九天雁翎(JTianLing) -- blog.csdn.net/vagrxie 讨论新闻组及文件 一. 综述 <异常处理与MiniDump详解(1) C++异常>稍 ...
- construction of tuples containing 0 or 1 items
[construction of tuples containing 0 or 1 items] the syntax has some extra quirks to accommodate the ...
- Effective Project Communications
I was recently invited to speak at a conference in Singapore on Effective Project Communications. I' ...
- 小王子浅读Effective javascript(一)了解javascript版本
哈哈,各位园友新年快乐!愚安好久没在园子里写东西了,这次决定针对javascript做一个系列,叫做<小王子浅读Effective javascript>,主要是按照David Herma ...
- [r]Seven habits of effective text editing
Seven habits of effective text editing(via) Bram Moolenaar November 2000 If you spend a lot of time ...
- Effective Tensorflow[转]
Effective TensorFlow Table of Contents TensorFlow Basics Understanding static and dynamic shapes Sco ...
- 04 Effective Go 高效的go语言 重点内容
Effective Go 高效的go语言 Introduction 介绍 Examples 例子 Formatting 格式 Commentary 评论 Names 名字 Package names ...
- <Effective C++>读书摘要--Designs and Declarations<一>
<Item 18> Make interfaces easy to use correctly and hard to use incorrectly 1.That being the c ...
- C++内存管理(effective c++ 04)
阅读effective c++ 04 (30页) 提到的static对象和堆与栈对象.看了看侯老师的内存管理视频1~3.有点深. 了解一下. 目录 1 内存管理 1.1 C++内存管理详解 1.1.1 ...
随机推荐
- Android中view动画
[1]透明 //点击按钮 实现iv 透明的效果 动画 public void click1(View v) { //1.0意味着着完全不透明 0.0意味着完全透明 AlphaAnimation aa ...
- 面向对象的static关键字(类中的static关键字)
转自:http://blog.csdn.net/xiayefanxing/article/details/7382192 http://www.cnblogs.com/SelaSelah/archiv ...
- C# 中的弱引用 WeakReference
C#中的弱引用(WeakReference) 我们平常用的都是对象的强引用,如果有强引用存在,GC是不会回收对象的.我们能不能同时保持对对象的引用,而又可以让GC需要的时候回收这个对象呢?.NET ...
- centos7 最小化安装 无 ifconfig,netstat 的安装
centos7 最小化安装 无 ifconfig,netstat 的安装 centos7 最小化安装之后,默认是没有 ifconfig,netstat命令的: 我们可以直接使用 yum -y inst ...
- CentOS报错:Could not retrieve mirrorlist http://mirrorlist.centos.org/?release=7&arch=x86_64&repo=os&infra=stock32 error was 14: curl#6 - "Could not resolve host: mirrorlist.centos.org; Unknown error"
今天安装完带图形界面的CentOS 7后,在Terminal中运行yum安装命令时报了以下错误: Could not retrieve mirrorlist http://mirrorlist.cen ...
- Columbia遗留问题
本来Columbia只是按照顺序,导航不可以点击,数组按照顺序push的小东西 在leader的要求下,要变成导航可以点击,无顺序的一团浆糊,经过了大概长达两天(我是不是太适合做程序!)的反复纠结,浆 ...
- jQuery+zTree加载树形结构菜单
jQuery+zTree加载树形结构菜单 由于项目中需要设计树形菜单功能,经过一番捣腾之后,终于给弄出来了,所以便记下来,也算是学习zTree的一个总结吧. zTree的介绍: 1.zTree 是利用 ...
- chrome 模拟点击
实现进入一个页面后触发一个<a>的点击事件. 由于safari和chrome不支持<a>的click()所以需要对浏览器进行判断 var Sys = {}; var ua ...
- POC测试——原型验证,降低风险,IT系统销售工作之一
POC测试,即Proof of Concept,是业界流行的针对客户具体应用的验证性测试,根据用户对采用系统提出的性能要求和扩展需求的指标,在选用服务器上进行真实数据的运行,对承载用户数据量和运行时间 ...
- 一段linux shell 代码涉及for循环和if esle
if [ 0 -ne $# ]; then echo "USAGE: prog [IN]input_file" >&2; exit 1;fisource /etc/p ...