• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            posts - 18,  comments - 104,  trackbacks - 0

            相信 xxx_cast 系列都很熟了。

            static_cast, dynamic_cast, const_cast, reinterpret_cast.

            但是當面對boost::shared_ptr的時候呢?

            reinterpret_cast 可以轉換任何類型,這個在討論范圍之外。

            對于下面的這個定義:

             1 class A
             2 {
             3 public:
             4     virtual ~A() {}
             5 };
             6 
             7 class B
             8     : public A
             9 {
            10 public:
            11     ~B() {}
            12 };

            如果用boost::shared_ptr包裝的話:

            1 typedef boost::shared_ptr<A> APtr;
            2 typedef boost::shared_ptr<B> BPtr;

            想想通常對指針的使用:
            1 *pA = new B();
            2 *pB = dynamic_cast<B*>(pA);
            3 // unsafe
            4 *upB = static_cast<B*>(pA);
            5 
            6 pA->;
            7 pB->;
            8 // may crash
            9 upB->;

            如果使用boost::shared_ptr呢。
            1 APtr pA = APtr(new B());    // OK
            2 BPtr pB = pA;               // compile error

            從根本上講,APtr 和 BPtr除了里面包裝的原生指針有點關系以外,他們就是完全不同的兩個類型,當然A和B也是完全不同的類型呀,可是想想看其實B是知道A的存在的。可是BPtr完全不知道APtr的存在。那這兒cast怎么進行呢?別說向下轉型了,向上轉型都成問題。

            看看這段代碼:

            1 template <class T>
            2 class shared_ptr
            3 {
            4     template <class F>
            5     shared_ptr(const shared_ptr<F>& p)
            6         : _p(p._p)
            7         , _np(p._np)
            8     {}
            9  private:
            10    T* _p;
            11    reference_counter _np;
            12 };

            這個構造函數可以搞定自動向上轉型,因為編譯器可以自動檢查 _p(p._p) 的合法性。那向下轉型怎么辦呢?看了上面這段代碼,相信很容易解決想想啊轉型的問題了。 只要把  _p(p._p)  改成 _p(dynamic_cast<T*>(p._p) 就可以了,當然要檢查指針的合法性,我就不多寫了。
            當然boost::shared_ptr的作者已經想到這個問題,他給提供了解決方案:


             1 template<class T, class U> 
             2 shared_ptr<T> static_pointer_cast(shared_ptr<U> const & r)
             3 {
             4     return shared_ptr<T>(r, boost::detail::static_cast_tag());
             5 }
             6 
             7 template<class T, class U> 
             8 shared_ptr<T> dynamic_pointer_cast(shared_ptr<U> const & r)
             9 {
            10     return shared_ptr<T>(r, boost::detail::dynamic_cast_tag());
            11 }

            需要用static_cast 轉換普通指針的地方,用shared_static_cast 轉換shared_ptr,
            需要用dynamic_cast 轉換普通指針的地方,用shared_dynamic_cast 轉換shared_ptr.

            前面說過,沒有const的shared_ptr,但是有


            1 const A* pA = new B();
            2 shared_ptr<const A> cpA(pA);         //const
            3 APtr spA = const_pointer_cast<A>(cpA);

            總結一下:
            const_cast               const_pointer_cast
            static_cast              static_pointer_cast
            dynamic_cast             dynamic_pointer_cast

            最后一個小問題:以前,boost中的shared_ptr的cast函數的名字是:shared_xxxx_cast,
            后來,為了IDE自動提供幫助,改成了xxxx_pointer_cast。由此可見,設計庫還是要用戶至上。

            posted @ 2009-04-30 21:43 尹東斐 閱讀(5208) | 評論 (2)編輯 收藏
            相信能看到這里的人,應該都用過std::endl吧,沒見過?

            1#include <iostream>
            2
            3using namespace std;
            4
            5int main()
            6{
            7    cout<<"Hello World!"<<endl;
            8}

            9

            就是hello world后面那個。到底這個endl是個什么東西呢? 答案是:函數指針。
            這是它的聲明:

            1template<class _Elem,
            2    class _Traits> inline
            3    basic_ostream<_Elem, _Traits>&
            4    endl(basic_ostream<_Elem, _Traits>& _Ostr)

            當然endl只輸入輸出流,輸入流沒有endl。所以輸出流需要一個類似

            basic_ostream& operator<<(basic_ostream&(*)(basic_ostream &))

            函數來接受這個endl。

            如果想寫個類,比如一個log類,希望可以像標準流一樣的輸出,需要做什么呢?

            1class Log
            2{
            3public:
            4    teamplate <typename T>
            5    Log& operator<<(const T& t)
            6    {
            7        // write t to log file.
            8    }

            9}
            ;

            有了這個定義后,Log類就可以像標準輸出流一樣用了,比如:

            1Log log;
            2log<<123<<"ABC"<<132.32<<endl;

            什么,編譯出錯,而且不止一個。上面說過,是endl引起的問題。
            std::endl的定義本身就是個模板函數,用一個模板函數(編譯時連參數都確定不下來)去推導模板參數,是極不現實的。
            因為:endl有兩個模板參數,_Elem 和 _Traits,其實_Traints 本身就是個以_Elem為參數的類模板,標準庫里面有兩個endl版本,
            一個是 _Elem = char, 另一個是 _Elem = wchar.
            所以編譯器不能推導出Log類的operator<<的模板參數T,于是就錯誤了。

            解決方案,之前也說過,需要一個接受函數指針的operator<<的重載版本。

            1Log& operator<<(basic_ostream<char, char_traits<char>>& (*_Pfn)(basic_ostream<char, char_traits<char>>&))
            2    {
            3            // write endl to log using _Pfn
            4    }

            有這個定義,就可以順利使用 <<std::endl 了。
            當然可以為wchar定義一個operator<<來使用寬字符,這都是函數重載惹的禍呀。因為char和wchar算是endl函數兩個重載版本。

            問題解決了,說一下,同樣的函數還有:

            ends,輸入一個字符串結束符。
            flush,刷新流。
            當然這倆個不常用。
            posted @ 2009-04-18 19:42 尹東斐 閱讀(4370) | 評論 (4)編輯 收藏
                 摘要: 為什么typedef的類型按照基類的聲明順序起作用?  閱讀全文
            posted @ 2009-04-09 23:40 尹東斐 閱讀(1879) | 評論 (13)編輯 收藏
                 摘要: static 變量初始化順序的問題和解決方案。  閱讀全文
            posted @ 2009-03-20 14:16 尹東斐 閱讀(4651) | 評論 (5)編輯 收藏
                 摘要: 如何保存C++的表達式結構。  閱讀全文
            posted @ 2009-03-11 20:23 尹東斐 閱讀(1396) | 評論 (3)編輯 收藏
                 摘要: 今天閑來無事,實現了一個簡版的boost::tuple作為練習,貼出來,僅供參考。  閱讀全文
            posted @ 2009-02-24 22:07 尹東斐 閱讀(1720) | 評論 (4)編輯 收藏
            先看看boost的實現吧。

             1 template<typename _T>
             2 struct wapper
             3 {};
             4 template <typename _T>
             5 _T&(* fun1(wapper<_T> t))();
             6 true_type fun1();
             7 
             8 class true_type{};
             9 class false_type
            10 {
            11     char c[8];
            12 };
            13 
            14 template<typename _T>
            15 true_type fun2(_T&(*)());
            16 false_type fun2();
            17 
            18 template<typename _T>
            19 struct is_reference
            20 {
            21     static const bool value = sizeof(fun2(fun1(wapper<_T>()))) == sizeof(false_type);
            22 };


            就是上面這個樣子,我做了一下簡化,更容易理解。

            下面是我的實現版本,最后再解釋。

             1 template<typename _T>
             2 class is_reference
             3 {
             4     template<typename _T>
             5     struct wapper
             6     {};
             7 
             8     class true_type{};
             9     class false_type
            10     {
            11         char c[8];
            12     };
            13 
            14     template <typename _T>
            15     static _T& fun1(wapper<_T>);
            16     static true_type fun1();
            17 
            18     template<typename _T>
            19     static true_type fun2(_T);
            20     static false_type fun2(true_type);
            21 public:
            22     static const bool value = sizeof(fun2(fun1(wapper<_T>()))) == sizeof(false_type);
            23 };

            用法如下:

            1 bool res1 = is_reference<char>::value;   //res1 == false
            2 bool res2 = is_reference<char&>::value;  //res2 == true

            函數參數會自動去掉引用比如:
            template<_T> void fun(_T a);
            無論任何時候,_T總是非引用類型。

            但是不讓函數通過函數參數直接推導模板參數的類型,就給函數參數加一個間接層wapper,
            類模板不會自動去掉引用,所以配合函數模板可以保證得到原來的類型。
             
            template<_T> void fun(wapper<_T> a);
            這時候,_T 就可能是引用類型了。因為c++不支持引用的引用,當模板函數中要用到引用的引用的時候,模板函數就會推導失敗。
            即,只要在函數fun的參數或者返回值里面含有_T&的話,fun就會推導失敗。從而編譯器會選擇 true_type fun(...);
            由于參數已經被用于推導模板參數,所以只能在返回類型中含有_T&,從而利用函數重載而區分引用和非引用。
            如果直接返回_T&類型,后面必須要定義只接受true_type類型參數的函數進行區分,因為_T&肯定是引用類型,所以后面接受
            false_type fun2(true_type)的函數會被選擇。

            但是遇到is_reference<true_type>::value怎么辦,我把他們都放到私有域了,永遠不會看到的,搞定。
            boost::trait中返回函數指針的解法也OK。因為char永遠不可能成功匹配函數指針。

            此方法的關鍵在于編譯器選擇重載函數的先后順序。
            而boost::trait中的方法是char永遠不能轉化成一個函數指針,從而選擇不同重載版本。

            解釋完畢。
            posted @ 2009-02-20 21:44 尹東斐 閱讀(2122) | 評論 (5)編輯 收藏

            關于boost::any,今天心血來潮,順手實現了一個。不想加有關type_info的東西,所以自我創造了一個用dynamic_cast的版本,僅供學習。
            要用當然要boost::any的嘛。

            關于模板,首先說兩條:

            1. 類模板
               (缺點)類模板不能自動推導模板參數(意思是當要用到某個模板類,比如A,那么你使用的時候一定要有模板參數,比如A<int>,編譯器不能自動推導),只能通過特化模板而是編譯器選擇合適的特化版本,
               (優點)類模板可以通過類模板把推導后的模板參數輸出,通常使用 typedef _Type value; 。

            2. 函數模板
               (優點)函數模板可以自動推導模板參數(意思是你頂一個模板函數,比如f,那么使用的時候不一定要有模板參數,比如f(123),編譯器會自動推導123為int),當然這里可以靠函數重載和編譯器匹配順序,來決定很多事情。
               (缺點)函數模板不能輸出推導后的類型。
             1 struct any
             2 {
             3     struct content
             4     {};
             5 
             6     template<typename _U>
             7     struct impl : public content
             8     {
             9         _U _u;
            10 
            11         impl(const _U& u)
            12             : _u(u)
            13         {}
            14 
            15         typedef _U type;    
            16     };
            17 
            18     template<typename _U>
            19     any(const _U& c)
            20         : _t(new impl<_U>(c))
            21     {}
            22 
            23     content* _t;
            24 };

            那么要實現any,any本身不是類模板,所以要接受任何參數,那么其構造函數必須是函數模板,但是函數模板不能導出推導后的類型,那么需要靠類模板來保存類型信息。


            1 struct any
            2 {
            3     template<typename _U>
            4     any(const _U& c)
            5     {}
            6 };

            可以看出,上面的any定義可以接受任何類型的參數,比如 any t1(1); any t2(1.0); 注意1和1.0不一樣。 但是輸入的東西沒有保存起來,起不到一個任意類型變量的作用(就是個空殼)。所以繼續修改,

             1 struct any
             2 {
             3 
             4     template<typename _U>
             5     struct impl
             6     {
             7         _U _u;
             8 
             9         impl(const _U& u)
            10             : _u(u)
            11         {}
            12 
            13         typedef _U type;    
            14     };
            15 
            16     template<typename _U>
            17     any(const _U& c)
            18         : _t(new impl<_U>(c))
            19     {}
            20 
            21     impl<???>* _t;
            22 };

            前面說過,類模板可以保存類型信息,所以加入了一個 impl 的類模板,通過any的構造函數推導出的類型,將參數的類型保存在impl里面。看到最后一樣的問號了吧,哪里要寫什么呢?
            any其實不知道他自己里面是什么東西呀,所以為了讓any知道,定義一個類A,然后讓impl繼承它,那么這個A就是所有impl<>的父類了,不管impl里面是什么,都是一個A。當然起名A不好聽,換個吧。

             1 #include <typeinfo>
             2 
             3 using namespace std;
             4 
             5 struct any
             6 {
             7     struct content
             8     {
             9         virtual ~content() {};
            10     };
            11 
            12     template<typename _U>
            13     struct impl : public content
            14     {
            15         _U _u;
            16 
            17         impl(const _U& u)
            18             : _u(u)
            19         {}
            20 
            21         typedef _U type;    
            22     };
            23 
            24     template<typename _U>
            25     any(const _U& c)
            26         : _pc(new impl<_U>(c))
            27     {}
            28 
            29     ~any()
            30     {
            31         delete _pc;
            32     }
            33 
            34     template<typename _T>
            35     _T& get()
            36     {
            37         impl<_T>* p = dynamic_cast<impl<_T>*>(_pc);
            38         if(0 == p)
            39             throw bad_cast();
            40         return p->_u;
            41     }
            42 
            43 private:
            44     content* _pc;
            45 };
            46 
            47 void main()
            48 {
            49     any a(10);
            50     any b(1.0);
            51     int x = a.get<int>();
            52     double y = b.get<double>();
            53 }


            現在可以看到, content代替了那個不知道些什么類型的???,這個技術名字叫類型消除技術,在boost里面用的很多,也算是一個經典的技術了。

            posted @ 2009-02-20 14:27 尹東斐 閱讀(2252) | 評論 (8)編輯 收藏
            僅列出標題
            共2頁: 1 2 
            <2025年5月>
            27282930123
            45678910
            11121314151617
            18192021222324
            25262728293031
            1234567

            常用鏈接

            留言簿(4)

            隨筆檔案

            文章分類

            文章檔案

            相冊

            好友博客

            搜索

            •  

            最新評論

            閱讀排行榜

            評論排行榜

            欧美久久久久久午夜精品| 伊人久久一区二区三区无码| 亚洲国产精品无码久久SM | 一本大道久久a久久精品综合| 精品午夜久久福利大片| 久久国产精品免费一区| 国内精品伊人久久久影院| 欧洲成人午夜精品无码区久久| 免费国产99久久久香蕉| 亚洲伊人久久综合中文成人网| 少妇久久久久久被弄高潮| 国内精品久久久久国产盗摄| 久久久亚洲AV波多野结衣| 人人狠狠综合久久亚洲婷婷| 国产99久久久国产精品小说| 狠狠狠色丁香婷婷综合久久俺| 国产精品亚洲综合久久| 国产综合成人久久大片91| 午夜不卡久久精品无码免费| 狠狠久久综合| 久久久精品免费国产四虎| 国内高清久久久久久| 久久综合狠狠综合久久97色| 国产精品久久免费| 亚洲va久久久噜噜噜久久男同 | 久久亚洲精品无码播放| 国产精品久久久久天天影视| 一本色道久久88精品综合| 亚洲综合久久久| 久久这里有精品视频| 91麻精品国产91久久久久| 久久精品国产69国产精品亚洲| 国产亚洲精久久久久久无码77777| 久久99精品久久久久久不卡| 久久免费高清视频| 久久99精品国产麻豆宅宅| 国产精品18久久久久久vr| 99久久精品国产麻豆| 久久福利青草精品资源站免费 | 怡红院日本一道日本久久 | 国产精品99久久久久久宅男小说|