CTP API的开拓措辞是C++,属于强类型措辞,哀求所有的类型在编译时都是确定的。就有两个问题须要办理:其一,API的功能实现逻辑须要封装到库文件里,由于暴露出来既不屈安,对客户端开拓者也不友好;其二,在编译好的库文件中,要能够调用进行客户端开拓时才实现的业务处理逻辑。
CTP API利用了虚函数沿着类的继续关系链向下穿透的性子,暴露两个基类CThostFtdcTraderAp和CThostFtdcTraderSpi的声明,实现了API的功能模块与客户端自定义业务处理模块的隔离。
对付API的功能模块而言,客户端自定义业务处理模块的类型是CThostFtdcTraderSpi,利用这个类型可以调用到业务处理逻辑。相应的,对付客户端自定义业务处理模块而言,API的功能模块的类型是CThostFtdcTraderApi,利用这个类型可以调用API的功能。

接下来,我们就来理解一下,什么是虚函数,以及虚函数是如何向下穿透的。
声明前加上virtual关键字的函数便是虚函数。虚函数的浸染是,利用父类类型的指针调用函数时,能够向下穿透到子类中的实现逻辑。当然,只有是先将子类实例化,然后将子类指针转成父类类型的指针,父类类型指针调用虚函数才能穿透到子类的实现。如果是父类直接实例化,用这个父类实例的指针调用虚函数,实行的仍旧是父类中的实现。
如果虚函数在声明时被赋值为0,就变成了纯虚函数,赋值为0是由于此处不须要实现。包含纯虚函数的类是纯虚类,常日被作为接口利用,以是也被称为接口类。由于纯虚类中声明的纯虚函数并没有被实现,以是纯虚类不能直接实例化,因此也被称为抽象类。
必须由一个继续了纯虚类的子类,将所有纯虚函数都实现,才能正常利用。首先将实现了所有纯虚函数的子类实例化,再将子类的指针转成基类类型的指针,利用该基类类型的指针就可以调用子类中实现的功能。
综上所示,基类通过(纯)虚函数实现了封装子类的目的。不同模块之间交互时,相互之间只须要利用基类类型的指针就可以调用须要的功能,不须要关心详细代码,实现了不同模块间代码的隔离。
1. CThostFtdcTraderApi
以CTP的交易API为例,CThostFtdcTraderApi便是被暴露出来的基类声明。库文件(dll/so)中存在一个实现了所有纯虚函数功能的子类,客户端开拓者不知道这个子类的详细内容,但是可以通过一个基类类型CThostFtdcTraderApi的指针调用这个子类中实现的API功能。
初始化阶段,首先利用CreateFtdcTraderApi得到的一个CThostFtdcTraderApi类型的指针。
可以想象天生这个指针的过程:首先,将库文件中实现API功能模块的子类实例化,该子类继续基类CThostFtdcTraderApi并且实现了所有纯虚函数的功能;然后,将该子类指针转成基类类型CThostFtdcTraderApi的指针,该基类类型指针作为结果被返回。客户端可以利用这个返回值调用API功能模块。
基类CreateFtdcTraderApi声明的虚函数,确保基类类型的指针可以穿透到子类的功能代码并实行。例如,客户端认证要求函数在CThostFtdcTraderApi类中的声明为:
这是一个纯虚函数。如下代码,在OnFrontConnected时,用m_pTraderApi实行ReqAuthenticate将客户端认证要求发往做事端。个中,m_pTraderApi是一个CThostFtdcTraderApi类型的指针,在初始化阶段通过CreateFtdcTraderApi得到。
2. CThostFtdcTraderSpi
CThostFtdcTraderSpi的情形类似。客户端开拓者可以实现一个子类,例如命名为CTraderSpiImpl,对涉及到的业务相应函数进行重载,实现详细的业务处理逻辑。
子类CTraderSpiImpl实例化之后,被转成基类类型CThostFtdcTraderSpi的指针,并注册RegisterSpi到API功能模块的实例中。
从实现的先后顺序来看,API事情线程在先,客户端业务相应处理逻辑在后。正是基类CThostFtdcTraderSpi声明时利用了虚函数,先实现的API事情线程中才能调用后实现的客户端业务处理逻辑。
以下代码演示了SPI如何被注册到API中:
API功能模块对客户端业务处理模块调用时,利用的是基类类型CThostFtdcTraderSpi,也便是被RegisterSpi注册到API中的指针。
在收到信息时,API事情线程利用这个指针实行干系的SPI函数。例如,前面给出的OnFrontConnected的定义。当收到OnFrontConnected信息时,API事情线程实行客户端定义的功能,例子中实行的便是发出认证要求。
CThostFtdcTraderSpi中定义的相应函数不是纯虚函数,有默认的实现,空函数。以是,CThostFtdcTraderSpi是可以被实例化的,但是这样做没故意义,由于默认不实行任何操作。子类不须要将所有的相应函数都重新实现一遍,只须要实现和业务干系的相应就可以了。不干系的业务相应时,调用默认的空函数。
CThostFtdcTraderSpi中声明的函数都因此On开头,表明都是回调函数。从命名规则上,由可以细分为以下几类:
OnRspQry/OnRspQuery,相应查询的回调函数,与一个查询要求ReqQry/ReqQuery对应。只有发起要求的会话连接能收到。OnRsp,相应非查询类业务的回调函数,与一个非查询类业务要求Req对应。也是只有发起要求的会话连接能收到。OnRtn/OnErrRtn,收到做事端主动推送的信息时的回调,也被称为关照。所有的会话连接都能收到。在不同的场景下,我们可能会提到回调、相应、关照、推送、触发等词,表达的都是API事情线程收到信息时实行由客户端定义的业务处理逻辑。