1. 什么样的接口才是好的接口 C++中充斥着接口:函数接口,类接口,模板接口.每个接口都是客户同你的代码进行交互的一种方法.假设你正在面对的是一些“讲道理”的人员,这些客户尝试把工作做好,他们希望能够正确使用你的接口.在这种情况下,如果接口被误用,你的接口应该至少负一部分的责任.理想情况下,如果使用一个接口没有做到客户希望做到的,代码应该不能通过编译:如果代码通过了编译,那么它就能做到客户想要的. 2. 编写好的接口的方法列举 2.1 使接口不容易被误用——通过引入新的类型 开发出容易被正确使…
让接口easy被正确使用,不easy被误用 如题目,我们自己的程序接口是面向用户的,程序的目的不可是解决这个问题,并且要让用户easy使用.所以.必须保证我们的程序接口具有非常强的鲁棒性. 怎么保证接口的鲁棒性,不同情况有不同的处理结果,作者列出了以下几个样例所相应的方法. 1.设计一个class来表示日期 class Date{ public: void Date(int month, int day, int year); -- }; 以上的构造接口非常easy被用户用错 Date d(30…
好的接口很容易被正确使用,不容易被误用.你应该在你IDE所有接口中努力达成这些性质. “促进正确使用”的办法包括接口的一致性,以及与内置类型的行为兼容. “阻止误用"的办法包括建立新类型.限制类型上的操作,束缚对象值,以及消除客户的资源管理责任. tri::shared_ptr支持定制型删除器(custom deleter).这可防范DLL问题,可被用来自动解除互斥锁(mutexes;见条款14)等等.…
举一个容易犯错的例子 class Date { private: int month; int day; int year; public: Date(int month,int day,int year) { this->month = month; ... } } //wrong example Date date(,,);//should be 3,30 Date date(,,);//should be 3,30 使用类型可避免这个问题 class Month { ... }; clas…
问题聚焦:     从这个条款开始,我们把注意力转移到软件设计和声明上来,具体的说就是,C++接口的设计和声明.     所谓软件设计,就是以一般习惯的构想开始,演变成细节的实现,最终开发针对性的特殊接口.     接口的设计和声明的一个最基本的准则是:让接口容易被正确使用,不容易被误用.     引入新类型是预防接口被误用的常见手段之一. 欲开发一个好的接口,首先必须考虑客户可能做出什么样的错误. 来看下面这个例子 class Date { public: Date(int month, in…
NOTE : 1.好的接口容易被正确使用,不容易被误用.应该让所有接口努力达成这些性质. 2.“促进正确使用”的办法包括接口的一致性,以及内置类型的行为兼容. 3.“阻止误用”的办法包括建立新类型/限制类型上的操作,束缚对象值,以及消除客户的资源管理责任. 4.tr1::shared_ptr 支持定制型删除器(custom deleter).这可以防范DLL问题,可以被用来自动解除互斥锁(mutexs)等等.…
1.别让异常逃离析构函数的原因 <Effective C++>第三版中条款08建议不要在析构函数中抛出异常,原因是C++异常机制不能同时处理两个或两个以上的异常.多个异常同时存在的情况下,程序若不结束,会导致不明确行为.如下代码: class Widget{ public: ~Widget(){...} //假设这个可能吐出一个异常 }; void dosomething(){ vector<Widget> v; } //v在这里被自动销毁 函数dosomething运行结束后,最…
□第一节 什么是接口?什么是接口?百度百科的解释:两个不同系统(或子程序)交接并通过它彼此作用的部分.接口的概念贯穿于整个软件开发过程中,本文讨论的接口概念仅局限于以C++实现的class,function等. class接口 以OOP的思想,现实的问题总能抽象成一个个class,这些class包含哪些属性,方法其实就是class接口要考虑的问题.function接口 class接口的操作就是通过一个个function来实现的,function的参数传递,返回值是function接口要考虑的问题…
(这里的验证结果是针对返回值优化的,其实和条款22本身所说的,考虑以操作符复合形式(op=)取代其独身形式(op),关系不大.书生注) 在[More Effective C++]条款22的最后,在返回值的返回方式上,大师Meyers推荐使用表达式[returnT(lhs)+=rhs;]这种使用匿名临时变量的方式,理由是“自古以来未具名对象总是比具名对象更容易被消除”,这种写法将更好地帮助编译器实现返回值优化(ReturnValue Optimization,简写RVO). 针对上述说法,我在两款…
More Effective C++ 条款0,1 条款0 关于编译器 不同的编译器支持C++的特性能力不同.有些编译器不支持bool类型,此时可用 enum bool{false, true};枚举类型来模拟bool类型.这允许参数类型为int和bool的函数重载,但是这样做的缺陷是,对于内置的比较运算符,其仍返回int类型. f(int);f(bool); f(a < b); // 会调用f(int),但其实用户期望调用f(bool). 但是一旦改用支持bool类型的编译器,情况可能会发生改变…
本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie 关联条款 Item 36 接口继承和实现继承不同.在 public 继承下, derived classes 总是继承 base class 的接口 class Shape{ public: virtual void draw() const = 0; virtual void error(const std::string &msg); int objectID() const; //.…
好的接口容易被正确使用,不易被误用 考虑以下函数: void func(int year,int month,int day){ //一些操作 } 这个函数看似合理,因为参数的名字已经暴露了它的用途.但是如果只有寒暑签名呢?如下: void func(int,int,int); 就算我告诉你,此处需要日期作为参数,你可能会以月日年.日月年等不同形式作为参数. 正确的做法是把年月日都各自抽象为一个类(或者说是结构体): struct Year { int year; }; struct Month…
classes和templates都支持接口(interface)和多态(polymorphism). 对classes而言接口是显式的(explicit),以函数签名为中心.多态则是通过virtual函数发生于运行期. 对template参数而言,接口是隐式的(implicit),奠基于有效表达式.多态则是通过template具现化和函数重载解析(function overloading resolution)发生于编译期.…
接口继承和实现继承不同.在public继承之下,derived classes总是继承base class的接口. pure virtual函数只具体指定接口继承. 简朴的(非纯)impure virtual函数具体指定接口继承及缺省实现继承. non-virtual函数具体指定接口继承以及强制性实现继承.…
test* create_test(); shared_ptr<test> create_test();//下面的接口比上面的接口要好 auto_ptr<test> create_test(); { shared_ptr<test> p(new test()); return p; }…
Class的设计就是type的设计.在定义一个新type之前,请确定你已经考虑过本条款覆盖的所有讨论主题. 新type的对象应该如何被创建和销毁? 对象的初始化和对象的赋值该有什么样的区别? 新type的对象如果被passed by value(以值传递),意味着什么? 什么是新type的“合法值”? 你的新type需要配合某个继承图系(inheritance graph)吗? 你的新type需要什么样的转换? 什么样的操作符和函数对此新type而言是合理的? 什么样的标准函数应该驳回? 谁该取…
//要点18: 如果函数在接口区定义了, 就无需用 forward 提前声明了 unit Unit1; interface uses   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,   Dialogs, StdCtrls; type   TForm1 = class(TForm)     Button1: TButton;     procedure Button1Click(Sender:…
避免返回handles(包括reference.指针.迭代器)指向对象内部.遵守这个条款可增加封装性,帮助const成员函数的行为像个const,并将发生“虚吊号码牌”(dangling handles)的可能性降至最低.…
绝不要返回pointer或reference指向一个local stack对象,或返回reference指向一个heap-allocated对象,或返回pointer或reference指向一个local static对象而有可能同时需要多个这样的对象.条款4已经为“在单线程环境中合理返回reference指向一个local static对象”提供了一份设计实例.…
条款27:尽量少做转型动作 单一对象可能拥有一个以上的地址!…
本节条款的题目是运用成员模板接受全部兼容类型 作者阐述自己的观点是通过智能指针的样例. 在学习本节条款之前我们要先明确关于隐式转化的问题 例如以下代码: #include<iostream> using namespace std; class A { public: explicit A(int i):a(i){}; A(const A&obj):a(obj.a) { } private: int a; }; int main() { int value =0; A a = valu…
我从本条款中学到了下面内容: 1.private继承不同于另外两种继承,派生类对象不能隐式转换为基类对象. 例如以下代码: class Bird//鸟 { }; class ostrich:private Bird//鸵鸟 { }; int main() { Bird *b = new ostrich();//编译不通过,基类不能转换为派生类 } 编译器明白指出基类是不可訪问的.所以转换失败. private继承在基类和派生类之间已经没有所谓的继承关系,之所以有它的存在纯粹是为应用层面服务,即为…
这个条款应该和第五个放在一起 编译器默认生成 1 无参构造函数, 2 析构函数 3 拷贝构造函数 4 赋值预算符 当我们不需要,就要显示的告诉大家我们不需要. 方法:自己声明这个函数为private,单不要定义它. 原因:1 自己声明这个函数,编译器就不会为我们生成这个函数 2 声明成private,就不会被对象误调用,但是freind和成员函数还是可以调用 3 声明但是不定义,当其他成员函数或者freind企图调用时就会发生编译错误…
本节条款的标题是:将与參数无关的代码抽离templates 学习本节条款首先须要明确一件事情,那就是模板实例化的过程会不会反复? 我们来举个样例: #include<iostream> using namespace std; template <typename T> T Try(T m) { return m; } int main() { Try(10); Try(1); } 我们看以上简单的代码.每一个人都知道模板被调用了两次,是的,这显而易见.但是模板也被实例化了两次吗?…
第十三条:使类和成员的可访问性最小化 一个设计良好的模块会将实现细节隐藏起来,只将暴露API.模块之间调用并不知道对象的细节.这个概念成为信息隐藏或封装.要注意一点,设计的一个方法或者其他什么,只要不是私有的,外面能访问,那么以后在重构重写的过程中,这个方法就不能删掉,即使只是某个方法中的一个过程.非零数组总是可变的,即使加了final,里面的内容也是可变的: public static final Thirteenth[] values = {new Thirteenth(), new Thi…
看上去最为简单的(public)继承的概念由两个单独部分组成:函数接口的继承和函数模板继承.这两种继承之间的区别同本书介绍部分讨论的函数声明和函数定义之间的区别完全对应. 1. 类函数的三种实现 作为一个类设计者,有时候你只想派生类继承成员函数的接口(声明).有时候你想让派生类同时继承接口和实现,但是你允许它们覆盖掉继承而来的函数实现.但有时候你却想让派生类继承一个函数的接口和实现并且不允许它们被覆盖掉. 为了对这些不同的选择有一个更好的理解,考虑表示几何图形的类继承体系: class Shap…
本节条款:须要类型转换时请为模板定义非成员函数 这节知识是在条款24的基础上,讲述的有关非成员函数在模板类中(non-member function template)的作用. 我们先看一下条款24讲述的知识核心.条款24讲述了我们怎样能实现类的对象在特定条件下的隐式转换问题. 我们先看以下代码: ** 例一: ** #include<iostream> #include<assert.h> using namespace std; class Rational { private…
尽量少做转型动作 尽量少做转型动作有什么目的?非常明显无非就是提高程序的稳定性.提高程序的运行效率. 那么.有哪些转型方式?每种方式都有什么弱点? 这是我们本节学习的重点. C++有四种转型: const_cast<T>(expression) dynamic_cast<T>(expression) reinterpret_cast<T>(expression) static_cast<T>(expression) 每种转型的作用例如以下: 1.const_…
(一) 为什么有人想要替换operator new 和 operator delete呢?三个常见的理由: (1)用来检測运用上的错误. (2)为了强化效果. (3)为了收集使用上的统计数据. (二) 以下是个高速发展得出的初阶段global operator new.促进并协助检測"overruns"或"underruns". static const int signature = 0xDEADBEEF; typedef unsigned char Byte;…
有时需要一些行为类似于函数指针的东西,但函数指针显得笨拙.危险而且过时(让我们承认这一点).通常最佳方式是使用函数对象(function object)取代函数指针. 与智能指针一样,函数对象也是一个普通的类对象.智能指针类型重载 -> 和 * (可能还有 ->* 和 .*)操作符,来模仿指针的行为:而函数对象类型则重载函数调用操作符“()”,来创建类似于函数指针的东西.考虑如下函数对象,它的每次调用都计算众所周知的斐波拉切数列(1,1,2,3,5,8,13,...)的下一个元素值: clas…