如何制作网站,顺义区做网站,森网站建设,东营做营销型网站建设条款18#xff1a;让接口更容易被正确使用#xff0c;不易被误用设计接口的原则#xff1a;正确性、高效性、封装性、维护性、延展性以及协议的一致性#xff1b;设计原则#xff1a;1#xff09;导入新类型来预防很多客户端的错误#xff0c;多使用系统类型#xff08…条款18让接口更容易被正确使用不易被误用设计接口的原则正确性、高效性、封装性、维护性、延展性以及协议的一致性设计原则1导入新类型来预防很多客户端的错误多使用系统类型type system划分为多个explicit函数如果某个变量的可选情况有限可以通过static函数来替代对象表示某个特定的对象并将对象的构造函数定义成private来防止新的对象生成具体代码如下
class  month{
public:static month Jan( ) {return month(1);}//以函数替代对象来代替某个特定的月份...
private:explicit month(int m);
};date(month::Jan( ));//调用2限制类型内什么事情可以做什么事情不可以做通常加上限制const;3)让你的types的行为和内置types行为一致提供行为一致的接口4使用智能指针来管理系统资源可以避免内存泄露注意智能指针的管理方式和管理条件单个对象并用自定义的deleter(资源释放函数)绑定在智能指针上deteler(可缺省代码如下std::tr1::shared_ptrinvestmentpinv(static_castinvestment*(0),getridofinvestment);//shared_ptr第一个参数必须要求是一个指针一个空指针shared_ptr//getridofinvestment为删除器
这样的初始化不是最优的先把pinv初始化为nullptr后对其进行赋值操作相当于初始化过程是多余的如果知道初始指针的话直接用初始指针来初始化pinv才是最优的使用智能指针的另外一个好的特性它会自动使用它的各一个指针专属的删除器因而消除一个潜在的客户错误cross-DLL problem,即对象在动态连接程序库DLL中被new创建却在另外一个DLL内被delete,这一类称为“跨DLL之new/delete成对运用”会导致运行期错误但是智能指针没有这个问题它缺省的删除器来自于智能指针诞生的那个delete;Boost的shared_ptr指针是原始指针raw pointer的两倍大以动态分配内存作为簿记用途和“删除器之专属数据”以vrtual形式调用删除器并以多线程程序修改引用次数时承受线程同步化的额外开销但这些额外的执行成本并不显著但是在降低客户错误的方面却起到了很好的效果
条款19设计class犹如设计type在设计一个新的class的时候就像设计一个新的type,在设计一个高效的class的时候应该考虑的问题有1对象如何被创建和销毁2对象初始化和赋值之间有什么差别3新对象在传值和传引用方面的考虑4对于成员变量引申的成员函数需要进行的错误检查工作及函数抛出异常及异常处理5考虑类型的继承和被继承情况6类型需要做什么样的转换编写对应的类型转换函数7什么函数应该是成员函数什么不是8什么函数应该定义为private;9)成员变量的属性9保证效率、异常安全性以及资源利用多任务锁定和动态内存10一般化你的类型考虑定义一个模板类11是否需要定义类可以在别人类的基础上添加一个或者多个non-member函数或者template;
条款20宁以pass-by-reference-to-const替换pass-by-value缺省情况下C以by-value方式传递对象到函数函数参数都是以实际实参的副本为初值而调用端所获得的也是函数返回值的一个附件这些副本由对象的copy构造函数产生使得pass-by-value称为一个函数操作如果有很多成员变量的时候如果采用传递引用的方式没有任何的构造函数或者析构函数调用因为没有任何的对象被创建除此之外以传引用的方式传递参数可以避免slicing(对象切割)的问题,即当一个对derived class对象以by value的方式传递并视为一个base class对象base class的拷贝构造函数被调用但是derived class区别于base class的部分会被切割掉而只留下一个base class;避免是slicing切割问题的方法就是采用by-reference-to-const的方式传递原因是因为reference往往是以指针的形式实现pass by reference通常意味着传递的是指针一般而言对于内置类型、STL的迭代器和函数对象采用传值比较方便其他最好使用传引用
条款21必须返回对象时别妄想返回其reference对于reference只是一个名称代表某个既有对象。任何时候看到一个reference声明式应该去了解它的另外一个名称是什么分析代码如下
//返回引用指向栈上的变量
错误方法1.const rational operator*(const rationallhs,const rational rhs){rational result(lhs.n*rhs.n,rhs.d*rhs.d);//试图返回一个栈空间变量为引用return result;                                   //对象在函数调用结束后被销毁引用指向一个错误的对象
}
//返回引用指向堆上的变量错误方法2.const rational operator*(const rationallhs,const rational rhs){rational *resultnew rational(lhs.n*rhs.n,rhs.d*rhs.d);//如何对这个new内存进行管理return *result;             //没办法取得reference背后的指针如何a*b*c时更容易出错
}
//返回引用指向一个函数内部的static rational对象错误方法3.const rational operator*(const rationallhs,const rational rhs){static rational result;    //staitc对象会导致多线程安全性resultrational temp(lhs.n*rhs.n,rhs.d*rhs.d);//static公用问题会带来错误的影响return result;            
}
rational a,b,c,d; if(a*bc*d)//if里面的数据一直为真不管其他的怎么取值因为static原因和返回是引用的原因
正确代码inline const rational operator*(const rationallhs,const rational rhs){rational result(lhs.n*rhs.n,rhs.d*rhs.d);//虽然会有拷贝构造和析构的成本但是对于安全性考虑却是一个很好的做法
}
结论不要返回pointer或者reference指向一个local stack对象见错误方法1或返回一个reference指向一个heap-allocated对象9见错误方法2或返回pointer或reference指向一个local static对象而有可能同时需要多个这样的对象见错误方法3
条款22将成员变量声明为private如果成员变量不是public,客户能够访问对象的方式就是通过成员变量函数如果public接口内的每样东西都是函数那么可以避免客户在调用class成员时考虑是否需要使用小括号如果你通过函数访问成员变量那么你以后你改变成员变量时class客户却完全不知道class 内部发生了变化将成员变量隐藏在函数接口的背后没可以为“所有可能的实现”提供弹性你对客户隐藏成员变量封装性你可以确定class的约束条件得到维护因为只有成员函数可以影响它们某个东西的封装性与“当其内容改变时可能造成的代码破坏量”成反比改变就是从class中移除它一旦你声明成员变量为public或者protected时就很难改变这个成员变量涉及的一切有太多的代码需要重写、重新测试、重新编写、重新编译结论将成员变量声明为private,这可以赋予客户访问数据的一致性、可细微划分访问控制、允诺约束条件获得保证并为class提供充分的实现弹性