溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

C++接口類工程化方法有哪些

發(fā)布時(shí)間:2021-11-24 11:02:03 來源:億速云 閱讀:129 作者:iii 欄目:互聯(lián)網(wǎng)科技

本篇內(nèi)容介紹了“C++接口類工程化方法有哪些”的有關(guān)知識(shí),在實(shí)際案例的操作過程中,不少人都會(huì)遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

接口分為調(diào)用接口與回調(diào)接口,調(diào)用接口主要實(shí)現(xiàn)模塊解耦的作用,只要保持接口兼容性,模塊內(nèi)部的升級(jí)對(duì)用戶可以做到無感知。良好的接口分層有助于各業(yè)務(wù)團(tuán)隊(duì)高效率開發(fā)。

回調(diào)接口主要用于系統(tǒng)有異步事件需要通知用戶。系統(tǒng)預(yù)定義接口形式,并由用戶注冊(cè),具體調(diào)用時(shí)機(jī)由系統(tǒng)決定。

調(diào)用接口

假設(shè)有一個(gè)網(wǎng)絡(luò)發(fā)送模塊類Network,類定義如下:

class Network{public:bool send();}

虛函數(shù)

最常用的就是虛函數(shù),可以使用虛函數(shù)定義Network接口類:

class Network{  public:  virtual bool send()=0  static Network* New();  static void Delete(Network* network_);}

將send定義為虛函數(shù),由繼承類去實(shí)現(xiàn)(比如由PLC模塊或者以太模塊繼承),以靜態(tài)方法創(chuàng)建子類對(duì)象,以基類Network的指針返回給業(yè)務(wù)使用。資源遵循誰創(chuàng)建誰銷毀的原則,基類還提供Delete方法銷毀對(duì)象。因?yàn)閷?duì)象銷毀封裝在接口內(nèi)部,因此Network接口類可以不需要虛析構(gòu)函數(shù)。

代碼使用虛函數(shù)易讀性較高,但是虛函數(shù)開銷較大(需要使用虛函數(shù)表指針間接調(diào)用),無法在編譯期間內(nèi)聯(lián)優(yōu)化,而事實(shí)上調(diào)用接口在編譯期就能確定使用哪個(gè)函數(shù),不需要用到虛函數(shù)的動(dòng)態(tài)特性。此外由于虛函數(shù)使用虛函數(shù)表指針間接調(diào)用的原因,增加虛函數(shù)會(huì)導(dǎo)致函數(shù)地址表索引變化,新增接口不能在二進(jìn)制層面兼容老接口。而且由于用戶可能繼承了Network接口類,在末尾增加虛函數(shù)也有風(fēng)險(xiǎn),因此虛函數(shù)接口一旦發(fā)布上線就基本無法修改。

指向?qū)崿F(xiàn)的指針

可以使用指向?qū)崿F(xiàn)的指針來定義Network接口類:

class NetworkImpl;class Network{  public:  bool send();  static Network* New();  Network()  ~Network();  private:  NetworkImpl* impl;}

Network的具體實(shí)現(xiàn)由NetworkImpl完成,通過使用指向?qū)崿F(xiàn)的指針的方式來定義接口,接口類對(duì)象的創(chuàng)建和銷毀可以由用戶負(fù)責(zé),更好的管理對(duì)象生命周期。

此外該方法通用性強(qiáng),新增接口不會(huì)影響二進(jìn)制兼容性,有利于項(xiàng)目快速迭代。

但是該方法還是增加了一層調(diào)用,對(duì)性能還是略微有影響,不符合C++的零開銷原則。

隱藏的子類

隱藏的子類思想很簡(jiǎn)單,接口要實(shí)現(xiàn)的目標(biāo)就是解耦,主要就是隱藏實(shí)現(xiàn),也就是隱藏接口類的成員變量。如果能將接口類的成員變量都轉(zhuǎn)移到另一個(gè)隱藏類中,那么接口類就不需要任何成員變量,那么就達(dá)到了隱藏實(shí)現(xiàn)的目的。具體實(shí)現(xiàn)方法如下:

class Network{  public:  bool send();  static Network* New();  static void Delete(Network* network_);  protected:  Network();  ~ Network();}

Network接口類只有成員函數(shù),沒有成員變量。提供靜態(tài)方法New創(chuàng)建對(duì)象,Delete方法銷毀對(duì)象。New方法的實(shí)現(xiàn)中會(huì)創(chuàng)建隱藏的子類NetworkImol的對(duì)象,并以父類Network指針的形式返回。NetworkImol類中定義了Network類的成員變量,并將Network類聲明為friend:

class NetworkImol:public Network{  friend class Network ;  private:  // 定義Network類的成員變量}

Network類的實(shí)現(xiàn)中創(chuàng)建NetworkImol子類對(duì)象,并以父類指針形式返回,通過將this強(qiáng)制轉(zhuǎn)換為子類NetworkImol類型的指針來訪問成員變量:

bool Network::send(){  NetworkImpl* impl = (NetworkImpl*)this;  //通過impl訪問成員變量,實(shí)現(xiàn)Network的功能}static Network* New(){  return new NetworkImpl();}static Delete(Network* network){  delete (NetworkImpl*)network;}

該方法符合C++零開銷原則,且同樣符合二進(jìn)制兼容性。

Rust語言中有一種Trait功能,可以在類外面實(shí)現(xiàn)一個(gè)Trait(不需要修改類代碼),那么C++同樣可以參考實(shí)現(xiàn)Trait功能假設(shè)需要在Network類中實(shí)現(xiàn)發(fā)送序列化數(shù)據(jù),重新設(shè)計(jì)Network接口,Serializable類定義如下:

class Serializable{public:  virtual void serialize()const =0;};

Network類定義如下:

class Network{public:  bool send(const char* host, uint16_t port,constSerializable& buf);}

Serializable接口類似于Rust中的Trait,現(xiàn)在任何實(shí)現(xiàn)了Serializable接口類的對(duì)象都可以通過調(diào)用Network類接口完成數(shù)據(jù)發(fā)送功能。那么問題來了,加入項(xiàng)目迭代需要增加通過Network類發(fā)送int型數(shù)據(jù),如何在不修改類定義的同時(shí)實(shí)現(xiàn)Serializable接口呢?很簡(jiǎn)單:

class IntSerializable  :public Serializable{public:IntSerializable(const int i):intthis(i){}virtual void serialize() const override{  buffer += std::to_string(*intthis);}private:  const int* const intthis;};

之后就可以通過Network發(fā)送int型數(shù)據(jù)了:

Network* network = Network::New();int i=1;network->send(ip,port, IntSerializable(i));

非侵入式接口將類和接口區(qū)分開來,類中的數(shù)據(jù)只包含成員變量,不包含虛函數(shù)表指針,因此類不會(huì)因?yàn)閷?shí)現(xiàn)了n個(gè)接口而引入n個(gè)虛函數(shù)表指針。而接口中只包含虛函數(shù)表指針,不包含數(shù)據(jù)成員,類和接口之間通過實(shí)現(xiàn)類進(jìn)行類型轉(zhuǎn)換,類只有在充當(dāng)接口使用的時(shí)候才會(huì)引入虛函數(shù)表指針,不充當(dāng)接口的時(shí)候不會(huì)引入,符合C++零開銷原則。

Rust編譯器通過impl關(guān)鍵字記錄了每個(gè)類實(shí)現(xiàn)了哪些Trait,因此在賦值時(shí)編譯器可以自動(dòng)完成將對(duì)象轉(zhuǎn)換為對(duì)應(yīng)的Trait類型。而g++等C++編譯器并沒有記錄這些轉(zhuǎn)換信息,因此需要手動(dòng)轉(zhuǎn)換類型。本質(zhì)上還是通過代碼幫編譯器記錄每個(gè)接口類實(shí)現(xiàn)了哪些Trait,使用模板類的繼承,在編譯期實(shí)現(xiàn)類似“靜態(tài)多態(tài)”的功能。

“C++接口類工程化方法有哪些”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

c++
AI