C++模板實現非侵入式多態
1 人贊了文章
對於以下討論的思考
虛函數是否是多餘的? - Graphene的回答 - 知乎
https://www.zhihu.com/question/280968276/answer/421051100
由於C++虛函數調用機制問題,不得不額外實現了一個proxy類,其實只是實現了一個智能指針的功能。但既然這麼幹了,一不做二不修,順便用模板實現一下自動類型轉換,讓調用更方便點,可以直接這麼調用:
std::vector<GraphProxy> gv; gv.push_back(Square() ); gv.push_back(Circle() );
這應該比 @Graphene 的PFA調用方式更簡潔直觀。同時我也實現了move語義,既管理了生命周期,又沒有增加額外的複製開銷。對比:
std::vector<static_proxy<Graph>> graphs;graphs.push_back(square{});graphs.emplace_back(std::in_place_type<circle>);
最終代碼(G++5.4.0通過):
#include <vector>#include <iostream>// 基類 作為多態基礎struct GraphBase{ virtual void printGraph() const { std::cout << "this is a Graph {}" << std::endl; } virtual GraphBase* copy() const { return new GraphBase(); } ~GraphBase() {}};// 模板類,作為提供「非侵入多態」功能的子類template <class T>struct Graph : T, GraphBase{ Graph(): T() {} Graph(const T& t): T(t) {} Graph(T&& t): T(std::move(t) ) {} Graph(const Graph& g): T(g) {} Graph(Graph&& g): T(std::move(g) ) {} virtual GraphBase* copy() const { return new Graph(*this); } virtual void printGraph() const { T::print(); } ~Graph() {}};// 代理類,實際調用者。// 其實相當於一個智能指針而已// 目的只是為了在實現多態的同時實現RAIIstruct GraphProxy{ GraphBase* _gobj; GraphProxy(): _gobj(nullptr) {} GraphProxy(const GraphProxy& gp) : _gobj( gp._gobj->copy() ) {} GraphProxy(GraphProxy&& gp) : _gobj( gp._gobj) { gp._gobj = nullptr; } GraphProxy& operator= (const GraphProxy& gp) { if (_gobj!=nullptr) delete _gobj; _gobj = gp._gobj->copy(); return *this; } GraphProxy& operator= (GraphProxy&& gp) { if (_gobj!=nullptr) delete _gobj; _gobj = gp._gobj; gp._gobj=nullptr; return *this; } template<class T> GraphProxy(const Graph<T>& g): _gobj(new Graph<T>(g)) {} template<class T> GraphProxy(Graph<T>&& g): _gobj(new Graph<T>(std::move(g)) ) {} template<class T> GraphProxy& operator = (const Graph<T>& g) { if (_gobj!=nullptr) delete _gobj; _gobj = new Graph<T>(g); } template<class T> GraphProxy& operator = (Graph<T>&& g) { if (_gobj!=nullptr) delete _gobj; _gobj = new Graph<T>(std::move(g)); g._gobj=nullptr; } void print() const { _gobj->printGraph(); } ~GraphProxy() { delete _gobj; }};// ----------------------// 定義具體的圖形類// 不需要繼承任何東西struct Square{ //順便檢查一下構造和賦值的調用 Square() { std::cout << "Square default ctor" << std::endl; } Square(const Square& s) { std::cout << "Square copy ctor" << std::endl; } Square(Square&& s) { std::cout << "Square move ctor" << std::endl; } Square& operator= (const Square& s) { std::cout << "Square copy assign" << std::endl; return *this; } Square& operator= (Square&& s) { std::cout << "Square move assign" << std::endl; return *this; } void print() const { std::cout << "this is a square []" << std::endl; }};struct Circle{ void print() const { std::cout << "this is a circle ()" << std::endl; }};// ----------------------// 實際調用int main(int argc, char* argv[]){ std::vector<GraphProxy> gv; gv.push_back(Graph<Square>() ); gv.push_back(Graph<Circle>() ); gv.push_back(Graph<Square>() ); gv.push_back(Graph<Circle>() ); for (const auto& g : gv) { g.print(); }}
//這段有錯誤,暫且保留struct GraphBase{ virtual void printGraph() const { std::cout << "this is a Graph {}" << std::endl; } ~GraphBase() {}};// 模板類,作為提供「非侵入多態」功能的子類template <class T>struct Graph : T, GraphBase{ Graph(): T() {} Graph(const T& t): T(t) {} Graph(T&& t): T(std::move(t) ) {} virtual void printGraph() const { T::print(); } ~Graph() {}};// 代理類,實際調用者。// 其實相當於一個智能指針而已// 目的只是為了在實現多態的同時實現RAIIstruct GraphProxy{ GraphBase* _gobj; template<class T> GraphProxy(const T& g): _gobj(new Graph<T>(g)) {} template<class T> GraphProxy(T&& g): _gobj(new Graph<T>(std::move(g)) ) {} void print() const { _gobj->printGraph(); } ~GraphProxy() { delete _gobj; }};
推薦閱讀:
※網路基本功(六):鏈路聚合
※科技早報:小米正式提交IPO 高盛即將啟動比特幣交易服務
※從經濟,軍事,科技看,印度超越中國有可能嗎?
※Catbook:做喵星人Facebook
※2799元大屏旗艦榮耀Note10發布,又有黑科技