1. 让自己习惯C++
条款1: 视C++为一个语言联邦
条款2: 尽量以const, enum, inline替换 #define
条款3: 尽可能使用const
条款4: 确定对象被使用前已先被初始化
条款5: 了解C++默默编写并调用哪些函数
条款6: 若不想使用编译器自动生成的函数,就该明确拒绝
可以将copy constructor or copy assignment声明为private,且不定义.
条款7: 为多态基类生命能够virtual析构函数
条款8: 别让异常逃离析构函数
析构函数抛出异常会导致不明确行为,在析构函数中捕捉.
条款9: 绝不在构造和析构过程中调用virtual函数.
class baseclass
{
baseclass()
{
func(); /*此时对象类型为baseclass, 调用的是baseclass中的func, 因为derivedclass变量尚未初始化,所以不可能调用derivedclass中的函数(会调用derivedclass中的变量)*/
}
virtual void func(void) const
{
}
};
条款10: 令operator= 返回一个reference to *this
条款11: 在operator= 中处理”自我赋值”
确定操作对象是同一对象时,其行为仍然正确.
条款12: 复制对象时,勿忘其每一个成分
条款13. 以对象管理资源
使用RAII对象,他们在构造函数中获得资源并在析构函数中释放资源,两个常被使用的RAII class是 tr1::shared_ptr和auto_ptr.
条款14: 在资源管理类中小心copying行为
shared_ptr和auto_ptr管理的是heap-based资源,有时候并不适合管理其他资源,所以你需要建立自己的资源管理类.
using namespace System;
using namespace System::Threading;
class Lock
{
public:
explicit Lock(Mutex *pm)
: mutexptr(pm)
{
lock(mutexptr);
}
~Lock()
{
unlock(mutexptr);
}
private:
Lock(const Lock &); //禁止复制
Mutex *mutexptr;
};
可以改写为:
class Lock
{
public:
explicit Lock(Mutex *pm)
: mutexptr(pm, unlock) /*shared_ptr允许指定删除器,一般为一个函数或者函数对象,当引用次数为0时,自动调用删除器,auto_ptr无,第二个参数默认为NULL*/
{
lock(mutexptr.get()); //获得资源
}
private:
Lock(const Lock &); //禁止复制
std::tr1::shared_ptr<Mutex> mutexptr;
};
条款15: 在资源管理类中提供对原始资源的访问
如同shared_ptr和auto_ptr,调用get()函数返回原始指针,或者使用隐式转换,将资源管理类转换为原始指针 operator ptr();
条款16: 成对使用new和delete时, 要采取相同形式
new – delete, new [] – delete []
条款17: 以独立语句将newed对象置入只能指针
func(std::tr1::shared_ptr<myclass>(new myclasss), func2());
也许编译器执行顺序为new, func2, call shared_ptr constructor, 如果func2异常,则new指针遗失且内存泄露.所以独立将new对象置入只能指针.
std::tr1::shared_ptr<myclass> ptr(new myclasss);
func(ptr, func2());
条款18: 让接口容易被正确使用, 不易被误用
条款19: 设计class犹如设计type
条款20: 宁以pass-by-reference-to-const替换pass-by-value
pass-by-value可能被切割,而引用往往以指针实现,pass by reference通常意味这真正传递的是指针,所以内置对象一般pass-by-value效率高些,也适用于STL的迭代器和函数对象,因为习惯上他们设定为passed by value.
条款21: 必须返回对象时,不要返回其reference
返回其副本,不能是局部变量的引用(销毁)或local static(同一内存)变量或者new(无法delete).
条款22: 将成员变量声明为private
条款23: 宁以non-member, non-friend替换member函数
条款24: 若所有参数皆需类型转换, 请为此采用non-member函数
class rational
{
public:
const rational operator *(const rational &rhs) const;
}
rational result;
rational onehalf;
result = onehalf*2; //ok, result.operator *(2);
result = 2*onehalf; //error, 2.operator *( result);
即使
class rational
{
public:
rational(int); //隐式转换
const rational operator *(const rational &rhs) const;
}
result = 2*onehalf; //error,因为只有当参数被列于参数列内,参数才可以进行隐式转换.
所以将operator *设为non-member函数
const rational operator *( const rational &lhs,const rational &rhs);
条款25: 考虑写出一个不抛异常的swap函数
如果在你的class中需要改写swap,那么也该提供一个non-member swap来调用前者.
class rational
{
public:
void swap(rational &)
{
using std::swap;
...
}
};
namespace std
{
template<> void swap<rational>(rational &a, rational &b)
{
a.swap(b);
}
}
如果rational是template
template <class T>class rational
{
public:
void swap(rational &)
{
using std::swap;
...
}
};
namespace std
{
template<class T> void swap(rational<T> &a, rational<Y> &b) /*重载, 但是error,可以特化std里面的templates,但是不可以添加新的templates或classed或functions或其他任何东西, std里面的东西完全由C++标准委员会决定.*/
{
a.swap(b);
}
}
namespace rationalstuf
{
template <class T>class rational
{
public:
void swap(rational &)
{
using std::swap;
//...
}
};
template<class T> void swap(rational<T> &a, rational<T> &b) //ok
{
a.swap(b);
}
}
条款26: 尽可能延后变量定义式的出现时间
条款27: 尽量少做转型动作
const_cast<T>(expression) //const转换为non-const
dynamic_cast<T>(expression) //安全像下转型,baseclass change to derivedclass
reinterpret_cast<T>(expression) //执行低级转换
static_cast<T>(expression) //强迫隐式转换
使用C++ stytle转型,不要使用就是转型,避免使用dynamic_cast
条款28: 避免返回handles指向对象内部成分
class myclass
{
public:
int &get(){return m_i;}
private:
int m_i;
};
降低对象封装性,而且有可能使用handle时,对象可能被析构.
条款29: 为"异常安全"而努力
当异常抛出时,不泄漏任何资源,不允许数据破换.
条款30: 透彻了解inlining的里里外外
inline和template都是编译器行为,被置于头文件中,因为inlining将函数调用替换为本体,所以需要知道函数定义,同样,template需要实例化也需要知道定义.
virtual函数会让inline落空,因为virtual是运行期决定,而inline是编译时决定.
inline无法随程序库的升级而升级,客户程序必须重新编译.
条款31: 将文件间的编译依存关系降至最低
相依于声明式,不要相依于定义式.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· 使用C#创建一个MCP客户端
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· Windows编程----内核对象竟然如此简单?