栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

决战深信服之系列二--泛型编程

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

决战深信服之系列二--泛型编程

了解编译期多态

多态分为编译期多态和运行期多态,编译期多态类似于决定哪个重载函数被调用,运行期多态决定哪个virtual函数被绑定。

//定义两家不同类型的company
class CompanyA {
pubic:
  void sendCleartext(const std::string& msg);
};
class CompanyB {
pubic:
  void sendCleartext(const std::string& msg);
};
 
class MsgInfo {...}; //定义消息类型
template
class MsgSender {
public:
...
  void sendClear(MsgInfo& info){
  std::string msg;
  company c;
  c.sendCleartext(msg);
}
};

MsgSender可以实现发送消息的作用。假设如果后面增加需求,比如在发送信息时增加日志信息,那么可用继承类增加这样的生产力:

template
class LogMsgSender: public MsgSender {
public:
  ...
  void sendClearLog(MsgInfo& info) {
  //增加log信息
  sendClear(info);
  }
};

这里继承类的接口sendClearLog与基类接口名sendClear不同,可以避免基类接口被遮掩。但是上述代码还是无法编译,显示找不到sendClear。原因是因为编译器在处理LogMsgSender时,在LogMsgSender被具现化之前是无法确认其继承的是什么类型的Company。而不知道Company是什么,就无法知道MsgSender是什么,也就无法知道其是否存在sendClear。

比如,因为模板可能被特化,而特化后的版本可能不提供和普通模板相同的接口,参考下例class:

class CompanyZ {
//不提供任何接口
};
template<>
class MsgSender {
public:
  ...
  void sendClear(MsgInfo& info){...} //这里使用单独的处理逻辑
};

上面MsgSender针对CompanyZ全特化了,重新回到前面的LogMsgSender,如果基类被指定为MsgSender,那么LogMsgSender::sendClearLog将无法通过编译,因为这个特化版本的class没有提供cendClear接口。

如何解决呢,对于继承类模板的子类,如果需要使用父类的非虚函数,有两种办法:

template
class LogMsgSender: public MsgSender {
public:
  ...
  void sendClearLog(MsgInfo& info){
    //增加log信息
    this->sendClear(); //假设sendClear将被继承
  }
};

第二种是使用using声明式:

using base::sendClear;

显式告诉编译器,假设sendClear位于base class内。using还有其他用途,比如防止基类接口名称被继承类接口名称遮盖。

这种这做法可以通过编译,但是如果对特化模板对象调用SendClearMsg,而特化模板没提供SendClear接口,还是不会通过编译。

将与参数无关的代码抽离templates

template可以避免相同功能的代码重复,但是在编写模版函数时需要将重复代码抽离出来,防止代码膨胀。

参考如下例子:

template 
class SquareMatrix{
public:
  ...
  void invert();
};

这个模板接受一个类型参数T,以及一个类型为size_t的非类型参数。

考虑如下代码:

SquareMatrix sm1;
sm1.invert();
SquareMatrix sm2;
sm2.invert();

这里仅仅因为size不同,就具现化两份invert函数,这就是template引起代码膨胀的例子。我们可以考虑为它们建立一个带数值参数的函数,从而不重复代码:

template 
class SquareMatrixbase{
public:
  void invert(std::size_t Size);
};
template 
class SquareMatrix: private SquareMatrixbase{
private:
  using SquareMatrixbase::invert;
public:
  //调用base class的invert
  void invert(std::size_t size) {this->invert(n);}
};

这里SquareMatrixbase只对矩阵元素对象的类型进行参数化,不对矩阵的尺寸进行参数化。

图灵完全

TMP模版元编程是图灵完全的,意味着可以用来声明变量、执行循环、编写及调用函数。

如使用模板可以在编译期计算阶乘:

template 
struct Factional{
  enum {value = n * Factional::value};
};
template <>  //特化
struct Factional<0>{
  enum {value = 1};
};

这里模版类采用“递归模版具现化”来取代循环,每个具现体都有一份自己的value。调用Factional的方法如下:

typename的双重意义

声明template参数时,前缀关键字class与typename可互换;

typename可标识从属类型名称,如下例:

template
void func(const C& container) {
...
//在行首加上typename,标识a是C的一个内部类型,而不是变量。
    typename C::a * x;
    ...
}

还有一个模版的全特化与偏特化,后续再写。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/708496.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号