Effective C++
爱吃红萝卜的小白兔
这个作者很懒,什么都没留下…
展开
-
条款 12
一,在派生类的copy构造函数中调用基类的copy构造函数class Base{private: string name; int age;public: Base(const Base& rhs):name(rhs.name), age(rhs.age){} Base& operator=(const Base& rhs){ name =原创 2017-05-24 17:09:33 · 300 阅读 · 0 评论 -
条款 11
一,在operator=中处理自我赋值class Bitmap{...};class Widget{private: Bitmap *p;public: Widget& operator=(const Widget& rhs){ delete p; p = new Bitmap(*rhs.p); return *this;原创 2017-05-23 20:32:50 · 234 阅读 · 0 评论 -
条款 09
一,不要在构造函数中调用virtual函数下面是一个类的继承体系,在基类的构造函数中,调用虚函数doSomething()。class Base{public: Base(){ ... doSomething(); } virtual void doSomething(){ ... }};class D原创 2017-05-23 19:27:41 · 222 阅读 · 0 评论 -
条款 08
一,析构函数中抛出异常带来的危害class Widget{public: ... ~Widget(){...}; //假设这个析构函数可能抛出异常};void doSomething(){ vector v; ...} //v在这里被自动销毁程序分析:当v被销毁时,其中放置的Widget对象会被逐个销毁。假设v中包含10个Widg原创 2017-05-23 16:18:10 · 228 阅读 · 0 评论 -
条款 07
一,为多态基类声明virtual析构函数下面是一个类的继承结构:class Base{};class Derived : public Base{};1,如果不把基类的析构函数声明为虚函数带来的问题Base *p = new Derived;指针p的编译时类型为Base类型,如果基类的析构函数是non virtual函数,当p的生命周期结束时,调用的是Base类的析构原创 2017-05-23 14:40:37 · 220 阅读 · 0 评论 -
条款 06
一,如何明确拒绝编译器自动生成的函数?如果一个类的对象是独一无二的,那么对这个类对象进行复制操作是没有意义的,那么我们应该怎么做可以禁止类的copy构造函数与copy assignment运算符?下面是我们的做法,将成员函数声明为私有的,并且故意不去实现它:class MyClass{public: ...private: ... MyClass(const原创 2017-05-23 14:13:11 · 234 阅读 · 0 评论 -
条款 05
一,C++默认编写与调用的函数当我们定义一个类时,如果我们自己没有声明,编译器就会为他声明一个copy构造函数、一个copy assignment运算符、和一个析构函数。此外,如果我们没有声明任何构造函数,编译器也生成一个default构造函数。只有这些函数被需要时,才会被编译器创建出来。原创 2017-05-23 14:03:16 · 222 阅读 · 0 评论 -
条款 04
一,确保对象使用之前已被初始化class Point{ int x; int y;};Point P;P的成员变量有时会被初始化为0有时不会,使用未被初始化的值会导致不明确的行为,因此要确保每一个构造函数都将对象的每一个成员初始化。二,不要混淆赋值与初始化1,不要混淆赋值与初始化下面自定义一个Person类class Person{private原创 2017-05-23 10:32:11 · 266 阅读 · 0 评论 -
条款 03
一,两个成员函数如果只是常量性不同,可以被重载。这是一个重要的C++特性,如果在一个类中有两个成员函数,这两个成员函数除了常量性不同其他都相同,他们的功能也是一样的,此时可以在non-const成员函数中,调用const成员函数。class TextBlock{public: const char& operator[](int index) const{ ret原创 2017-05-23 09:57:38 · 289 阅读 · 0 评论 -
条款 01 - 视C++为一个语言联邦
一,视C++为一个语言联邦 C++是一门威力强大的语言,带着众多的特性,支持面向过程、面向对象、泛型编程,C++是由相关的语言组成的联邦而非单一语言。二,C++的强大之处提供了丰富的类型与运算符。支持面向对象的三大特性。灵活的内存分配机制,提供了new与delete运算符,进行内存的分配与释放。支持泛型编程,STL便是泛型编程的典型应用。...原创 2018-08-22 08:12:56 · 154 阅读 · 0 评论 -
条款 13
一,以对象管理资源1,以对象来管理资源这里有一个类的继承体系,所有的类都继承自Base class。之后创建一个工厂函数,创建特定的Base对象。Base *create(); //返回指针,指向Base继承体系中动态分配的对象,调用者有责任删除它为了确保create()返回的资源总是释放,我们需要将资源放到对象里,当对象的生命周期结束时,对象的析构函数会自动释放那些资源。原创 2017-05-24 17:42:20 · 247 阅读 · 0 评论 -
条款 16
一,使用new与delete时,采取相同的形式1,如果采用不同的形式带来的问题string *p = new string[100];delete p;程序分析:上面的程序会导致不明确的行为,p所包含的100个对象中有99个不太可能被正确释放,因为他们的析构函数有可能没被调用。2,new与delete实际进行的操作当我们使用new动态创建一个对象时,会有两件事情发生,原创 2017-05-24 19:31:32 · 197 阅读 · 0 评论 -
条款 18
一,让接口容易被使用,而不易被误用1,导入新的类型预防客户端错误下面是我们定义的用来表示日期的classclass Date{public: Date(int month, int day, int year); ...};对于上面这个自定义的类,用户很容易犯下面这些错误第一,使用错误的顺序传递参数Date(30, 3, 2017);第二,传递一个无效的月份原创 2017-05-24 20:22:09 · 210 阅读 · 0 评论 -
条款 02
一,宏定义的基本用法1,简单的宏定义#define 例:#define PI 3.14159262,带参数的宏定义#define () 例: #define sum(a, b) (a)+(b)二,使用#define带来的问题例如有下面这个宏定义:#define MAX_VAL 1.234名称MAX_VAL从未被编译器看到过,因为在编译器处理原创 2017-05-23 08:56:25 · 216 阅读 · 0 评论 -
条款 49
一,new-handler的行为1,STL的内存分配STL容器所使用的内存是由容器所拥有的分配器对象管理,不是被new和delete直接管理。2,理解new-handler的行为当new无法满足用户的内存需求,在抛出一个错误之前,它会调用一个客户指定的错误处理函数,就会所谓的new-handler。为了指定这个用以处理内存不足的函数,客户必须调用set_new_handle原创 2017-05-31 14:31:50 · 296 阅读 · 0 评论 -
条款 34
一,下面是一个几何类的继承体系在Shape类中声明一个pure virtual函数draw()、一个impure virtual函数error()、一个non virtual函数objectID()。class Shape{public: virtual void draw() const = 0; virtual void error(string&); int原创 2017-05-27 14:44:36 · 338 阅读 · 0 评论 -
条款 35
一,应用场景假设我们在设计一款游戏,我们为游戏中的人物设计一个继承体系,不同的人物有不同的计算健康程度的方法,因此我们在基类中声明一个虚函数class GameCharacter{public: virtual int healthValue() const; //返回人物的健康指数};二,使用Strategy模式替换虚函数//前置声明class GameC原创 2017-05-25 16:08:55 · 314 阅读 · 0 评论 -
条款 33
一,避免遮掩继承而来的名称下面是一个类的继承结构,derived class继承了声明于base class内的所有东西,derived class作用域被嵌套在base class作用域内。以作用域为基础的名称遮掩规则并没有改变,因此base class内所有名为func1与func3的函数都被derived class内的func1与func3函数遮掩掉了,因此会有下面的输出结果:cl原创 2017-05-25 15:33:29 · 299 阅读 · 0 评论 -
条款 32
一,继承模塑的是is-a关系1,public继承意味"is-a"适用于每一个base class身上的每一件事情也适用于derived class身上,因为每一个derived class对象也都是一个base class对象。2,原创 2017-05-25 15:06:34 · 214 阅读 · 0 评论 -
条款 30
一,理解inline1,inline函数,看起来像函数,比宏定义好用,同时又不会承受函数调用带来的开销。对每一个inline函数的调用,都会使用函数本体代替之,这样做会增加目标代码的体积。2,inline只是对编译器的一个申请,不是强制命令。这项申请可以隐喻提出,也可以显示提出。隐喻方式是将函数定义于class定义式内。显示的方式是在,函数原型前面加上inline关键字。原创 2017-05-25 14:33:13 · 297 阅读 · 0 评论 -
条款 26
一,尽可能延后变量定义式的出现时间如果我们定义了一个变量而其类型带有一个构造函数或析构函数,那么当程序运行到这个变量的定义时,首先我们得承受构造成本,当这个变量离开其作用域时,我们得承受析构成本。即使这个变量从头到尾都没有用到,仍需耗费这些成本。下面是一个对字符串进行加密的函数:首先会检查给定的字符串的长度,如果长度小于设定的值,直接返回空串;否则对给定的字符串进行加密,然后返回加密后的字符串原创 2017-05-25 11:36:46 · 273 阅读 · 0 评论 -
条款 22
一,将成员变量声明为private1,如果成员变量声明为private,客户端唯一可能访问成员变量的方法就是通过成员函数。使用成员函数访问成员变量,可以让我们对成员变量的处理有精准的控制。如果我们把成员变量声明为public,每个人都可以读写它。但是如果我们把成员变量声明为private,然后通过成员函数来访问,我们就可以实现出"只读访问"、"读写访问"、"不准访问"。2,通过成员原创 2017-05-25 09:46:40 · 264 阅读 · 0 评论 -
条款 20
一,使用传递对象的引用替换对象传值1,传递对象的引用,带来更高的效率class Date{public: Date(int month, int day, int year); ...};//传值void doSomething(Date d){ ...}Date s(10, 2, 2016);doSomething(s);程序分析:上面原创 2017-05-24 20:39:44 · 215 阅读 · 0 评论 -
条款 02 - 尽量以const、enum、inline替换#define
一,宏定义的基本用法1.1,简单的宏定义#define <宏名> <字符串>例:#define PI 3.14159261.2,带参数的宏定义#define <宏名> (<参数表>) <宏体>例: #define sum(a, b) (a)+(b)二,使用#define带来的问题 这个条款告诉...原创 2018-08-22 09:31:33 · 166 阅读 · 0 评论