网站建设和维护待遇怎样,高大上网站建设公司,建筑课堂首页,win7 iis 默认网站属性条款41#xff1a;了解隐式接口和编译期多态面向对象编程世界总是以显式接口#xff08;源码可见的接口#xff09;和运行期多态#xff08;virtual#xff09;解决问题#xff1b;对于templates及泛型编程的世界#xff0c;隐式接口和编译期多态显得更加重要#xff1…条款41了解隐式接口和编译期多态面向对象编程世界总是以显式接口源码可见的接口和运行期多态virtual解决问题对于templates及泛型编程的世界隐式接口和编译期多态显得更加重要对于template只有当参数具体确定时具现化才能确定具体操作而这些具现化的行为发生在编译期以不同的template参数具现化function templates会导致调用不同的函数这就是所谓的编译期多态。通常显示接口由函数的签名式函数名称参数类型返回类型构成而隐式接口则不基于函数签名式它是由有效表达式组成表达式自身看起来很复杂但它们要求的约束条件一般而言直接而又明确template参数身上的隐式接口和class对象上的显示接口都是在编译器完成检查对template参数而言接口是隐式的基于有效表达式多态则是通过template具现化和函数重载解析发生于编译器
条款42了解typename的双重意义在声明template类型参数时class和typename意义完全相同引申template内出现的名称如果相依于某个template参数称之为从属名称如果从属名称在class内呈嵌套状我们称它为嵌套从属名称如c::const_iterator就是这样的名称它其实是一个嵌套从属类型名称也就是个嵌套从属名称并指涉某类型如果一个名称(int)并不依赖于template参数的名称这样的名称称为谓非从属名称代码如下
templatetypename c
void print2nd(const ccontainer)
{if(container.size()2){c::const_iterator iter(container.begin( ));iter;int value*iter;}
}嵌套从属名称会导致编译困难如c::const_iterator *p;C解析代码有一个规定如果解析器在template中遭遇一个嵌套从属名称它便假设这个名称不是个类型除非你告诉它是所以缺省情况下嵌套从属名称不是类型有一个例外正确的情况就是告诉C解析器这个一个类型在名称前加关键字typename就可以了typename只被用来验明嵌套从属类型名称其他名称不该有它的存在typename作为嵌套从属类型名称的前缀词有一个例外typename不可以出现在base classes list内的嵌套从属结构也不可在member initialization list成员初始列表中作为base class修饰符如
template typename T
class derived:public baseT::Nested{
publicexplicit derived(int x):baseT::Nested(x){typename baseT::Nested temp;}
};
条款43学习处理模块化基类内的名称考虑如下的程序代码
template typename company templatetypename company
class msgsender{ class loggingmsgsender:public msgsendercompany{
public public:void sendclear(const msginfo info) void sendclearmsg(const msginfo info){{std::string msg; sendclear(info);//调用base class函数代码编译不通过company c;c.sendcleartext(msg); }} };
};分析当编译器遇到class template loggingmsgsender定义式并不知道它继承什么样的class当然它继承的是msgsendercompany,但其中的company是个template参数不到后来loggingmsgsender被具现化无法确切知道它是什么也就不知道是否有sendclear这个函数C编译器拒绝调用sendclear的原因它知道base classtemplates有可能被特化而那个特化的版本不提供和一般性template相同的接口解决C不进入templatized base classes的方法有三种1在base class函数调用之前加上this-,也就是this-sendclear(info);2)使用using声明式告诉编译器sendclear在base class内如using msgsendercompany::sendclear;3)明确指出被调用函数位于base class内如msgsendercompany::sendclear(info);但是如果调用的是virtual函数那么就会关闭virtual绑定行为
条款44将与参数无关的代码抽离templatestemplates是节省时间和避免代码重复的一个奇方妙法但是使用templates可能会导致代码膨胀其二进制码带着重复的代码数据可以通过使用共性和变性分析的方法解决这个问题将多个class的共同部分搬离到新的class并通过继承或复合的方式来得到公共属性任何templates代码都不该与某个造成膨胀的templates参数产生相依的关系因非类型模板参数而造成的代码膨胀往往可消除做法是以函数参数或class成员变量替换templates参数如矩阵类求逆实现因类型参数而造成的代码膨胀往往可以降低做法是让带有完全相同二进制表述的具现类型共享实现代码如int和long实现如果你实现某些成员函数而他们操作强型指针如T*,你应该令他们调用另一个操作无类型指针void *的函数后者完成实际工作
条款45运用成员函数模板接受所有兼容类型真实指针支持隐式转换如derived class隐式转换成base class但是同一个templates的不同具现体之间并不存在什么与生俱来的固有关系如某个带有base-derived关系的B,D两类型分别具现某个template产生的两个具现体并不带有base-derived关系C给我们提供一个称为member function templates它为模板类提供构造函数这一类构造函数通过对象u创建对象t而u和t的类型是同一个template的不同具现体我们称这个函数为泛化构造函数如
templatetypename T
class smartptr{
public:templatetypename usmartptr(const smartptru other);
};但是对于泛化构造函数有时我们需要指定隐式转换的方向例如我们不能将int *转换为double*这时候我们可能需要一个指针指向class的原始数据这样问题就变成只有存在两个底层指针可以转换的才是我们需要的结果member function templates成员函数模板的效果不限于构造函数它还支持赋值操作如shared_ptr类的代码
templatetypename T
class shared_ptr{
public:templateclass Yexplicit shared_ptr(Y* p);//没有const原因templateclass Yshared_ptr(shared_ptrYconstr);//没有explicit允许隐式转换templateclass Yexplicit shared_ptr(weak_ptrYconstr);templateclass Yexplicit shared_ptr(auto_ptrYr);//没有constauto_ptr性质决定templateclass Yshared_ptroperator(shared_ptrYconst r);templateclass Yshared_ptroperator(auto_ptrYr);//没有constauto_ptr性质决定}member function templates会声明一个泛化的copy构造函数和copy assignment操作符但是它不会改变C语言的规则C语言规定如果程序需要一个copy构造函数你没有声明编译器会自动帮你生成一个相同规则也适用于赋值操作因此如果你不想让系统声明正常的拷贝构造函数和赋值操作符你得自己声明
条款46需要类型转换时请为模板定义非成员函数当不存在模板时如果函数参数都存在隐式转换则需要将这个函数定义成非成员函数当存在模板时这条规则又发生了变化编译无法通过因为在template具现化实参推导过程中从不将隐式类型转换函数纳入考虑解决的方法利用friend关键字将非成员函数声明为友元函数新用法同时提供实现实现在函数外通过友元函数调用这样可以实现代码冲击最小化如果只是单纯提供友元声明那么可以通过编译却没有办法完成连接这种称为混合式代码调用代码调用成功的原因是函数在被调用的过程中参数可以实现隐式变换类模板的声明式为templatetypename T class rational;