![](https://img-blog.csdnimg.cn/20201014180756927.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
effective c++
文章平均质量分 51
beecindy
hi
展开
-
条款41:了解隐式接口和编译期多态
1、显式接口和执行期多态 对于 classes(类),interfaces(接口)是 explicit(显式)的并以 function signatures(函数识别特征)为中心的。polymorphism(多态性)通过 virtual functions(虚拟函数)出现在运行期。class Widget {public: Widget(); virtual ~原创 2010-03-27 12:30:00 · 393 阅读 · 0 评论 -
条款40:明智而谨慎地使用多重继承
1、多重继承的歧义性问题class BorrowableItem { // something a library lets you borrowpublic: void checkOut(); // check the item out from the library ..};class ElectronicGadget {private: bool c原创 2010-03-25 17:57:00 · 371 阅读 · 0 评论 -
条款39:明智而审慎地使用private继承
private继承其实意味着implemented-in-terms-of(根据某物实现出)。如果你写的class Derived以private继承自class Base,你的用意是为了让 Dervived类采用到Base类中的某些特性,而不是因Dervied对象与Base对象存在一些观念上的关系。 关于is-implemented-in-term-of(根据某物来实现原创 2010-03-25 16:52:00 · 412 阅读 · 0 评论 -
条款13:以对象管理资源
问题代码://没有走到DELETE一部,如中间过程有RETURN语句void f(){ Investment* pInv = creatInvestment(); ... delete pInv;} 解决:智能指针。把资源放入对象内,利用析构函数确保释放。1、资源取得时机便是初始化时机"(Resource Acquisition Is Initializatio原创 2010-01-06 09:00:00 · 259 阅读 · 0 评论 -
条款37:绝不重新定义继承而来的缺省参数值
问题代码:class Shape{public: enum Color{RED,GREEN,BLUE}; virtual void draw(Color color = RED)const = 0; ...};class Circle:public Shape{public: virtual void draw(Color color = GREEN)c原创 2010-03-19 18:00:00 · 350 阅读 · 0 评论 -
条款36:绝对不要重新定义继承而来的non-virtual函数
class b {public: void mf(); ...};class d: public b {public: void mf(); // hides b::mf; see item33 ...}; 如果你在编写 class d 而且你重定义了一个你从 class b 继承到的非虚拟函数mf,d的objects将很可能表现原创 2010-03-19 17:15:00 · 407 阅读 · 0 评论 -
条款38:通过复合塑膜出has-a或"根据某物实现"
1、has-aclass Address{...};class PhoneNumber{...};class Person{ ...private: std::string name_; Address address_; PhoneNumber voiceNumber_; PhoneNumber faxNumber_;}; Pers原创 2010-03-19 18:31:00 · 383 阅读 · 0 评论 -
条款34:区分接口继承和实现继承
作为一个 class 的设计者class Shape {public: virtual void draw() const = 0;//1 virtual void error(const std::string& msg);//2 int objectID() const;//3 ...}; 1、有的时候你想要 derived classes 只继承一个原创 2010-03-15 13:50:00 · 351 阅读 · 0 评论 -
条款32:确定你的public继承塑模出is-a关系
class Person {...};class Student: public Person {...};我们从日常的经验知道每一个学生都是一个人,但并不是每一个人都是一个学生。这就是由这个继承体系严格确定的意义。 public inheritance 和 is-a 等价听起来简单,但有时你的直觉会误导你。class Rectangle {...};class原创 2010-03-15 11:47:00 · 280 阅读 · 0 评论 -
条款35: 考虑virtual函数以外的选择
class GameCharacter {public: virtual int healthValue() const; // return characters health rating; ... // derived classes may redefine this}; 选择方案一原创 2010-03-15 15:22:00 · 316 阅读 · 0 评论 -
条款42:了解typename的双重意义
1、两个概念template // print 2nd element invoid print2nd(const C& container) // container;{ // this is not valid C++! if (container.size() >= 2) { //nested dependent name C::const_iterator原创 2010-03-28 14:24:00 · 361 阅读 · 0 评论 -
条款51:编写new和delete时需固守常规
很多人没有意识到operator new成员函数会被derived classes继承,那就会出现,有可能base class的operator new被调用用以分配derived class对象。因此derived class的operator new的代码建议:struct Base{ static void* operator new(std::s原创 2010-04-12 09:43:00 · 402 阅读 · 0 评论 -
条款48:认识template元编
template // general case: the value ofstruct Factorial { // Factorial is n times the value // of Factorial enum { value = n * Factorial::value };};template<> // special case: the value ofs原创 2010-04-05 20:45:00 · 705 阅读 · 0 评论 -
条款45:运用成员函数模板接受所有兼容类型
继承体系之间的转换操作:class Top{ ... };class Middle:public Top{...};class Bottom:public Middle{...};Top* top1 = new Middle; //将Middle*转换为Top*Top* top2 = new Bottom; //将Bottom*转换为Top*co原创 2010-04-05 12:59:00 · 367 阅读 · 0 评论 -
条款43:学习处理模板化基类内的名称
问题提出:templateclass MsgSender{public: ... void sendClear(const MsgInfo& info){ std::string msg; ...//根据info产生信息 Company c; c.sendClearText(msg); } void sendSecret(const原创 2010-04-03 16:33:00 · 316 阅读 · 0 评论 -
条款47:请使用traits classes表现类型信息
STL迭代器可分为五类: struct input_iterator_tag{};struct output_iterator_tag{};struct forward_iterator_tag:public input_iterator_tag{};struct bidirectional_iterator_tag:public forward_iterator_tag{};原创 2010-04-05 19:26:00 · 448 阅读 · 0 评论 -
条款46:需要类型转换时请为模板定义非成员函数
问题提出:templateclass Rational{public: Rational(const T& numberator = 0, const T& denominator = 1); const T numerator()const; const T denominator()const; ...};templateconst Rational o原创 2010-04-05 17:25:00 · 417 阅读 · 0 评论 -
条款44:将与参数无关的代码抽离templates
问题提出:这个 template(模板)取得一个 type parameter(类型参数)T,但是它还有一个类型为 size_t 的参数——一个 non-type parameter(非类型参数)。template<typename T, // template for n x n matrices ofstd::size_t n> // objects of type T; s原创 2010-04-03 18:58:00 · 417 阅读 · 0 评论 -
条款55:让自己熟悉 Boost
Boost有两点被认为是其它组织所不能比拟的。首先,它唯一地与 C++ 标准委员会之间有着紧密和有影响力的关系。Boost是由委员会成员所创建,且现在 Boost成员与委员会成员之间继续保持着许多的交迭。除此之外,Boost的目标之一就是为可能加入到C++标准中的能力但当测试环境。这一切的结果是 14个新加入到 TR1 (看条款 54) 中的库有超过 2/3 以 Bo原创 2010-04-16 11:52:00 · 617 阅读 · 0 评论 -
条款54:让自己熟悉包括TR1在内的标准程序库
tr1::shared_ptr:引用计数性质的智能指针。注意不能应用循环引用情况 tr1::weak_ptr:不对shared_ptr引用计数进行影响的“弱”指针,可以和shared_ptr搭配使用以解决资源的循环引用问题。当shared_ptr因引用计数为0而被释放时,相关的weak_ptr自动标记为无效。 tr1::function:delegate在C++原创 2010-04-16 11:41:00 · 606 阅读 · 0 评论 -
条款52:写了placement new也要写placement delete
当你在写一个new表达式像这样: Widget* new_widget = new Widget; 共有两个函数被调用:一个是用以分配内存的operator new,一个是Widget的default构造函数.那么假设我们现在遇到的情况是:第一个函数调用成功,第二个函数却抛出异常.按照常理,在步骤一中所分配的内存必须取消,否则就会造成内存原创 2010-04-12 11:09:00 · 481 阅读 · 0 评论 -
条款49:了解new-handler的行为
我们知道new操作符私底下通过调用operator new来实现内存分配的。当operator new无法满足内存申请时,它会不断调用new-handler函数,直到找到足够内存。而客户是通过set_new_handler将自己的new-handler传递给它的。struct Widget{ static std::new_handler set_new_handler( s原创 2010-04-11 10:40:00 · 272 阅读 · 0 评论 -
条款33:避免遮掩继承而来的名称
问题代码:class Base {private: int x;public: virtual void mf1() = 0; // virtual void mf1(int); // overload virtual void mf2(); void mf3(); void mf3(double); // overload ...};class原创 2010-03-15 13:08:00 · 272 阅读 · 0 评论 -
条款28:避免返回handles指向对象内部成分
1、避免返回对象内部构件的句柄(引用,指针,或迭代器)。这样会提高封装性,帮助const成员函数产生const效果。class Point {// class for representing points public: Point(int x, int y); ... void setX(int newVal); void setY(int原创 2010-03-10 11:12:00 · 298 阅读 · 0 评论 -
条款12:复制对象时勿忘其每一个成分
确保你在复制对象时,复制所有成员变量。当你增加一个新的成员变量时,要同时修改copying构造函数和copying assign运算符操作,如果你忘记,编译器不会去提醒你的。 任何时候只要你承担起为子类撰写COPYING函数的重大责任,必须很小心地也复制其父类成分,那些成分往往是PRIVATE。 PriorityCustomer::PriorityCustomer原创 2009-12-30 22:55:00 · 265 阅读 · 0 评论 -
条款23:宁以non-member、non-friend替换member函数
主要原因:non-member、non-friend带来的封装性比member函数高。 例如C++的做法:结合了namespace/ header "webbrowser.h" - header for class WebBrowser itself// as well as "core" WebBrowser-related functionalitynamespace We原创 2010-03-02 09:28:00 · 326 阅读 · 0 评论 -
条款5:了解C++默默编写并调用哪些函数
C++处理类时,当它需要时,它会为类声明一个COPY构造函数,一个COPY ASSIGNMENT操作符和一个析构函数。没有构造函数,会声明一个DEFAULT构造函数。 类中成员含有引用变量时,复制拷贝存在问题。原创 2009-12-22 18:40:00 · 332 阅读 · 0 评论 -
条款4:确定对象被使用前已先被初始化
赋值与初始化的区别:赋值操作完成类似伪初始化工作。 构造函数的一个较佳写法是,使用member initialization list。通常效率较高。省下了default构造函数设初值一步。 函数内的static对象称为local static对象,其他static对象称为non-local static对象。对于不同编译单元内的non-local static对象的初始化顺原创 2009-12-21 18:20:00 · 334 阅读 · 0 评论 -
条款3:尽可能使用const
修饰常量const出现在星号左边:const widge* pw = widget const * pwconst_iterator 修饰指针const出现在星号左边:widge * const pwconst std::vector::iterator iter = vec.begin(); 便用const和non-contst成员函数。并避免代码重复的方法原创 2009-12-21 13:46:00 · 266 阅读 · 0 评论 -
条款2:尽量以CONST,ENUM,INLINE替换#DEFINE
类中定义常量:static const int numturns = 5;这是声明式而非定义式。若不需取它们的地址,无须提供定义式。定义式如下:const int GamePlayer::NumTurns; 一个class需要常量值,定义如下:enum{NumTurns = 5};int scores[NumTurns]; 关于“形似函数的宏,最好改用i原创 2009-12-20 23:35:00 · 312 阅读 · 0 评论 -
条款21:必须返回对象时,别妄想返回其reference
问题代码://错误inline const rational& operator*(const rational& lhs, const rational& rhs){ rational result(lhs.n * rhs.n, lhs.d * rhs.d); return result;}//极容易内存漏露inline const ratio原创 2010-02-28 16:37:00 · 307 阅读 · 0 评论 -
条款20:宁以pass-by-reference-to-const替换pass-by-value
pass-by-value的问题:1、多次的构造析构,成本高。2、造成对象切割问题 但内置类型、STL的迭代器、函数对象(?),pass-by-value方式往往比较适合。原创 2010-02-28 16:00:00 · 491 阅读 · 1 评论 -
条款17:以独立语句将NEWED对象置入智能指针
错误代码:processWidget(std::tr1::shared_ptr(new Widget), priority()); 原因:若编译器最终获得这样的操作序列:1、执行“ new Widget()”2、调用priority3、调用shared_ptr的构造函数但万一对priority的调用导至异常,会发生什么事情?内存泄漏。 正确代码:原创 2010-02-08 18:00:00 · 286 阅读 · 0 评论 -
条款18: 让接口容易被正确使用,不易被误用
1、好的接口很容易被正确使用,不容易被误用.你应该在你的所有接口中努力达成这些性质.2、"促进正确使用"的办法包括接口的一致性,以及与内置类型的行为兼容.问题代码:class Date{public: Date(int month,int day,int year); ...}; 修改:struct Day{ explicit Day(int dayValue):v原创 2010-02-09 23:17:00 · 317 阅读 · 0 评论 -
条款15: 在资源管理类中提供对原始资源的访问
将RAII class对象转换为其所含原始资源,有两个做法:显示转换和隐式转换 显示:std::trl::shared_ptrpInv(createInvestment());int daysHeld(const Investment* pi);int days = daysHeld(pInv);//错误int days = daysHeld(pInv.get());//正原创 2010-02-05 10:34:00 · 368 阅读 · 0 评论 -
条款24:若所有参数皆需类型转换,请为此采用non-member函数
Rational class:class Rational {pbulic: Rational(int numerator = 0, int denominator = 1); //注意这个构造函数不为explicit int numerator() const; int denominator() const; //两个接口 提供对成员的访问priavte: ..原创 2010-03-03 16:48:00 · 313 阅读 · 0 评论 -
条款6:若不想使用编译器自动生成的函数,就该明确拒绝
你怎么可以复制某些先天独一无二的东西呢?如 认为HomeForSale h3(h1) 或 h1 = h2 对某项任务是不合符情理时,此时,目标是阻止COPYING的发生。方法是将这些函数声明为private,且只有声明即可。同样,可以使用Uncopyable这样的base class,这个class内无成员函数,能避免了对COPYING的调用。class Uncopyable {原创 2009-12-23 17:29:00 · 262 阅读 · 0 评论 -
条款11: 在operator= 中处理"自我赋值"
问题代码:class Bitmap{};class Widget{public: ... Widget& operator=(const Widget& rhs){ delete hBitmap; hBitmap_ = new Bitmap(*rhs.hBitmap_); return *this; }private: B原创 2009-12-29 23:28:00 · 301 阅读 · 0 评论 -
条款31:将文件间的编译依存关系降至最低
Handle 类和 Interface 类从实现中分离出接口,因此减少了文件之间的编译依赖。编译依赖关系:如果不访问 Person 的实现使用到的类,也就是 string,Date 和 Address 的定义,类 Person 就无法编译class Person {public: Person(const std::string& name, const Date& birthda原创 2010-03-12 13:33:00 · 562 阅读 · 0 评论 -
条款30:透彻了解inlining的里里外外
一个 inline 函数背后的思想是用函数本体代替每一处对这个函数的调用,过分热衷于 inline 化会使得程序对于可用空间来说过于庞大,在另一方面,如果一个 inline 函数本体很短,为函数本体生成的代码可能比为一个函数调用生成的代码还要小。 inline 是向编译器发出的一个请求,而不是一个命令。这个请求能够以显式的或隐式的方式提出。隐式的方法就是在一个类定义的内部原创 2010-03-12 13:23:00 · 342 阅读 · 0 评论