Effective C++第四章-设计与声明-1
来源:互联网 发布:企业网络搭建方案文档 编辑:程序博客网 时间:2024/05/17 07:20
多态类型
多态类型在作为接口时有数据保护和隐藏的效果。
多态分为两种:通用多态和特定多态
通用多态:对工作的类型不加限制,允许对不同类型的值执行相同的代码
又分为参数多态(parametric)和包含多态(inclusion)
参数多态:采用参数化模板,通过给出不同的类型参数,使得一个结构有多种类型。例如,模板类。
包含多态:同样的操作可用于一个类型及其子类型(注意是子类型,不是子类)。包含多态一般需要进行运行时的类型检查。例如,虚函数“virtual—override”机制。
特定多态:只对有限数量的类型有效,而且对不同类型的值可能要执行不同的代码
又分为过载多态(overloading)和强制多态(coercion)
- 强制多态:编译程序通过语义操作,把操作对象的类型强行加以变换,以符合函数或操作符的要求。程序设计语言中基本类型的大多数操作符,在发生不同类型的数据进行混合运算时,编译程序一般都会进行强制多态。程序员也可以显示地进行强制多态的操作(Casting)。举个例子,比如,int+double,编译系统一般会把int转换为double,然后执行double+double运算,这个int->double的转换,就实现了强制多态,即可是隐式的,也可显式转换。
- 过载(overloading)多态:同一个名(操作符﹑函数名)在不同的上下文中有不同的类型。程序设计语言中基本类型的大多数操作符都是过载多态的。通俗的讲法,就是c++中的函数重载。
PS:类(class)和类型(type)的区别
type包括两种:
基本类型
int、char、double、bool、unsigned等等
复合类型
class、struct、function、array数组、reference引用、union联合体、enum枚举类型。他们基本上都是一个type里面有很多其他的type。所以class是类型type的一种,type是一个抽象的概念。
cross-DLL problem
- 这个问题发生于“对象在一个DLL(动态链接程序库)中被new创建,却在另一个DLL内被delete销毁”。在许多平台上,这一类“跨DLL之new/delete成对运用”会导致运行期错误。
- tr1::shared_ptr不会有该问题,因为它缺省的删除器是来自“tr1::shared_ptr诞生所在的那个DLL”的delete。例如:
//Stock类派生自Investment类std::tr1::shared_ptr<Investment> CreateInvestment(){ return std::tr1::shared_ptr<Investment>(new Stock);}//返回的那个tr1::shared_ptr可被传递给任何其它DLLs,无需在意“cross_DLL problem”。这个指向Stock的tr1::shared_ptrs会追踪记录“当Stock的引用次数变为0时该调用那个DLL's delete”
最常见的tr1::shared_ptr实现品来自Boost。
Boost的shared_ptr是原始指针的两倍,以动态分配内存作为薄记用途和“删除器之专属数据”,以virtual形式调用删除器,并在多线程程序修改引用次数时蒙受线程同步化的额外开销。(只要定义一个预处理器符号就可以关闭多线程支持)。总之,它比原始指针大且慢,而且使用辅助动态内存。在许多应用程序中这些额外的执行成本并不显著,然而其降低客户错误的成效却是每个人都看得到。
导入新类型来预防“接口被误用”
举例:
class Data{public: Data(int month,int day,int year); ...};...Data d(30,3,1994);//wrong以错误的次序传递参数Data d(2,30,1994);//wrong传递参数不符合要求
导入新类型:
struct day{ explicit Day(int d):val(d){} ... int val;};struct month{explicit month(int m):val(m){}...int val;};struct year{explicit year(int y):val(y){}...int val;};class Data{public: Data(const month& m,const day& d,const year& y); ...};//调用Data d(30,3,1995);//wrongData d(day(30),month(3),year(1995));//wrongData d(month(3),day(30),year(1995));//right
也可以在新类型中限制其值:
class month{public: static month Jan(){return month(1);} static month Feb(){return month(2);} ...private: explicit month(int m); ...};Data d(month::mar(),day(30),year(1993));
定义一个新的type需要考虑的问题:
(定义一个新的class也就是定义一个新的type)
新type的对象应该如何被创建和销毁?
对象的初始化和对象的赋值该有什么样的差别?
构造函数和赋值操作符的差异
新type的对象如果被passed by value(以值传递),意味着什么?
copy构造函数用来定义一个type的passed by value该如何实现
新type的“合法值”
新type需要配合某个继承图系吗?
如果你继承自某些既有的classes,就受到那些classes的设计的束缚,特别是受到其函数是virtual或non-virtual的影响;
如果你允许其他classes继承你的class,那会影响你所声明的函数-尤其是析构函数是否为virtual。
新type需要什么样的转换?
如类型转换函数、可被单一实参调用的构造函数
什么样的标准函数应该驳回?(声明为private者)
谁该取用新type的成员?
帮助你决定哪个成员为public,哪个为protected,哪个为private
什么是新type的“未声明接口”?
新的type有多么一般化?
如果你定义的是一整个types家族,则应该定义一个新的class template。
by reference-to-const代替by value
“昂贵”的by value
缺省情况下C++以by value方式传递对象至函数。函数参数都是以实际实参的复件为初值,而调用端所获得的也是函数返回值的一个复件。这些复件由对象的copy构造函数产生。
昂贵的例子:
class Person{public:Person();private:std::string name;std::string address;};class Student:public Person{public:Student();~Student();private:std::string schoolname;std::string schooladdress;};bool validatestudent(Student s);//声明...Student pla;bool plaIsOk = validatestudent(pla);//调用函数//该例子中的by value方法传递一个Student对象会导致调用一次Student copy构造函数、一次Person copy构造函数、四次string copy构造函数。当函数中Student复件被销毁,会调用六次对应的析构函数.
一般而言,可以合理假设by value不昂贵的唯一对象就是内置类型和STL的迭代器和函数对象。
以by reference方式传递参数也可以避免对象切割问题:当一个derived class对象以by value方式传递并被视为一个base class 对象,base class的copy构造函数会被调用。而“造成此对象的行为像个derived class对象”的那些特化性质全被切割掉了,仅仅留下一个base class对象。
例:
class window{public:...std::string name() const;//返回窗口名称virtual void display() const;//显示窗口};class windowwithscroll:public window{public:...virtual void display() const;};
现在有一个函数:
void printNameanddisplay(window w)//参数可能被切割:参数w被构造成一个window对象。传入的wws是windowwithscroll对象。{ std::cout<<w.name();//调用的是window类型的name函数 w.display();//调用的是window类的display函数}//当调用上述函数windowwithscroll wws;printNameanddisplay(wws);
解决对象切割的方法:以by reference方式传递参数
void printNameanddisplay(const window& w){ std::cout<<w.name();w.display();}
返回reference可能出现的错误
任何时候看到一个reference,一定是指向某个既有的对象。
例:
class rational{public: rational(int numerator = 0 , int denumerator = 1); ...private: int n,d;//分子:numerator,分母:denumerator const rational operator*(const rational& le,const rational& ri);//以by value方法返回的是一个对象};
一个“必须返回新对象”的函数的正确写法
inline const rational operator* (const rational& le,const rational& ri){rational rational(le.n * ri.n , le.d * ri.d);}
函数创建新对象并返回reference的错误写法:
在stack空间(local变量是在stack空间创建对象)
const rational& operator*(const rational& le,const rational& ri){rational result(le.n * ri.n , le.d * ri.d);return result;}//local变量result会在函数退出前被销毁;
任何函数如果返回一个reference指向某个local对象,都是错误的。
在heap空间(new创建)
const rational& operator*(const rational& le,const rational& ri){ rational *result = new rational(le.n * ri.n , le.d * ri.d); return result;}//问题在于谁该对new出来的对象实施delete?
静态存储区(定义函数内部的static对象)
const rational& operator*(const rational& le,const rational& ri){static rational result;result = ...;return result;}
bool operator==(const rational& le,const rational& ri);...rational a,b,c,d;if((a*b)==(c*d)){}//此时(a*b)==(c*d)永远为TRUE。
- 《Effective C++》第四章:设计与声明
- Effective C++第四章-设计与声明-1
- (Effective C++)第四章 设计与声明(Design and declaration)
- Effective C++第四章-设计与声明-2
- 【读书笔记】Effective C++—4 设计与声明(之1)
- Effective C++(四)设计与声明
- effective C++: 4.设计与声明
- Effective C++(四)接口设计与声明
- <<Effective C++>>读书笔记4: 设计与声明
- 《Effective C++》设计与声明章节
- Effective C++读书笔记 第四部分 设计与声明
- Effective C++ 笔记 第四部分 设计与声明
- 第四章 设计与声明
- 第四章 设计与声明
- 第四章 类和函数:设计与声明(Effective C++ Second Edition 读书笔记)
- 【effective c++读书笔记】【第4章】设计与声明(1)
- 《Effective C++》设计与声明:条款18-条款19
- Effective C++ -- 设计与声明
- 3D Morphable Model Method
- 10张图带你深入理解Docker容器和镜像
- redis本地测试环境安装windows
- Integer.valueOf()方法 java
- 路线更改事件 $ROUTECHANGESTART 与 $LOCATIONCHANGESTART
- Effective C++第四章-设计与声明-1
- 专业名词解释
- 通过OpenCV修改图片某一像素的数值 Python实现
- MFC pictur控件下显示Mat图片
- 再见“小明爬楼梯”问题
- 【Java】打包Jar包并用脚本执行
- IP数据报格式详解
- ASA policy-map配置
- 阿里移动技术三驾马车Weex/Atlas/ACCS,路由