• <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>
            首先,any類里面一定要提供一個模板構造函數和模板operator=操作符。其次,數據的存放之所是個問題,顯然你不能將它保存在any類中,那會導致any類成為模板類,后者是明確不被允許的。結論是:為容器準備一個非泛型的基類,而讓指針指向該基類。

            動機

            C++是強類型語言,所有強類型語言對類型的要求都是苛刻的,類型一有不合編譯器就會抱怨說不能將某某類型轉換為某某類型,當然如果在類型之間提供了轉換操作符或是標準所允許的一定程度的隱式轉換(如經過非explicit構造函數創建臨時變量的隱式轉換或是在intlong這些基本類型間的)又另當別論。總的說來,為了保持類型安全,C++有嚴厲的要求。然而有時候程序員可能有這樣的需要:

             

            int i;

            iong j;

            X x; // 假設X為用戶定義的類

             

            any anyVal=i;

            ... //use anyVal as a int value

             

            anyVal=j;

            ... //use anyVal as a long value

             

            anyVal=x;

            ... //use anyVal as a long value

             

            考慮這樣的一個泛型指針類該如何設計是很有趣的事情。

             

            1. 它本身不能是模板類,因為如果它是模板,你必須為它的具現化提供模板參數。而事實上你并不想這樣做。你想同一個對象接受任意類型的數據。在上面的代碼中這個對象是anyVal。然而,如果你必須為它提供模板參數,那么上面的代碼看起來就會像這樣:

             

            any<int> anyIntVal=i;

            any<long> anyLongVal=j;

            ...

             

            這顯然已經喪失了anyVal的優勢——以單個對象接受所有類型的數據。與其這樣還不如直接寫:

             

            int anyIntVal=i;

            int anyLongVal=j;

             

            所以,any不能是模板類。

             

            2. 它必須提供某些有關它所保存的對象類型的信息。

             

            3. 它必須提供某種方法將它保存的數值取出來

             

            事實上,boost庫已經提供了這樣的類boost::any,下面我就為你講述它的原理及構造。

             

            boost::any原理與結構

            首先,any類里面一定要提供一個模板構造函數和模板operator=操作符。因為你必須允許用戶寫出:

             

            any any_value(val); //val 的類型為任意的

            any_value=val1; //val1 類型也是任意的

             

            這樣的代碼。

             

            其次,數據的存放之所是個問題,顯然你不能將它保存在any類中,那會導致any類成為模板類,后者是明確不被允許的。數據應該動態存放,即動態分配一個數據的容器來存放數據,而any類中則保存指向這個容器的指針,明確地說,是指向這個容器的基類的指針,這是因為容器本身必須為模板,而any類中的指針成員又必須不是泛型的(因為any不能是泛型的,所以any中所有數據成員都不能是泛型的),所以,結論是:為容器準備一個非泛型的基類,而讓指針指向該基類

             

            下面就看一看boost庫是如何具體實現這兩點的。

             

            摘自”boost/any.hpp”

             

            class any

            {

            public:

             

            class placeholder // 泛型數據容器holder的非泛型基類  

            {                   

            public:

            // 虛析構函數,為保證派生類對象能用基類指針析構

            virtual ~placeholder(){}

             

            public:

              // 提供關于類型的信息

            virtual const std::type_info & type() const = 0;

            virtual placeholder * clone() const = 0;  // 復制

            }; // placeholder

             

            template<typename ValueType>

            class holder : public placeholder

            {

            public:

            holder(const ValueType & value)

            : held(value)

            {}

            public:

            virtual const std::type_info & type() const

            {

              // typeid返回std::typeinfo對象引用,后者包含任意對象的類型信息, name,此外還提供operator==操作符你可以用typeid(oneObj)==typeid(anotherObj)來比兩個對象之類型是否一致。

            return typeid(ValueType); 

            }

             

            virtual placeholder * clone() const

            {

            return new holder(held);  // 改寫虛函數,返回自身的復制體

            }

             

            public:

            ValueType held; // 數據保存的地方

            }; // holder

             

            // 指向泛型數據容器holder的基類placeholder的指針

            placeholder * content;

             

            //模板構造函數,動態分配數據容器并調用其構造函數

            template<typename ValueType>

            any(const ValueType & value)

            : content(new holder<ValueType>(value))

            {}

            ...

            // 與模板構造函數一樣,但使用了swap慣用手法

            template<typename ValueType>

            any & operator=(const ValueType & rhs)

            {

            // 先創建一個臨時對象any(rhs),再調用下面的swap函數進行底層數據交換,注意與*this交換數據的是臨時對象,所以rhs的底層數據并未被更改,只是在swap結束后臨時對象擁有了*this的底層數據,而此時*this也擁有了臨時對象構造時所擁有的rhs的數據的副本。然后臨時對象由于生命期的結束而被自動析構,*this原來的底層數據隨之煙消云散。

            any(rhs).swap(*this);

            return *this;

            }

             

            any & swap(any & rhs) //swap函數,交換底層數據

            {

            std::swap(content, rhs.content); // 只是簡單地將兩個指針的值互換

            return *this;

            }

             

            ~any()  //析構函數

            {

              //釋放容器,用的是基類指針,這就是placeholder需要一個虛析構函數的原因

            delete content;

            }

            ...

            };

             

            這雖然并非any的全部源代碼,但是所有重要的思想已經表露無遺。剩下的部分只是一些簡單的細節,請參見boost庫的原文件。

             

            但是等等!,你急切的說:你失去了類型的信息。...的確,當賦值的模板函數返回后你也就失去了關于類型的信息。考慮下面你可能想要寫出的代碼:

             

            int i=10;

            boost::any anyVal=i;

             

            int j=anyVal;

            // error,實際上你是想把anyVal賦給另一個int型變量,這應該以某種方式被允許,但決不是在any類中提供轉換操作符,因為你事先并不知道要用anyVal來承載何種類型的變量,所以轉換操作符無從給出。

             

            當轉換操作符的設想徹底失敗后,我們只能借助于某些外來的顯式轉換操作。就向static_cast<>一樣。boost提供了any_cast<>,于是你可以這樣寫:

             

            int j=any_cast<int>(anyVal);

             

            事實上,any_cast的代碼是這樣的:

             

            template<typename ValueType>

            ValueType any_cast(const any & operand)

            {

              // 調用any_cast針對指針的版本。

            const ValueType * result = any_cast<ValueType>(&operand);

             

            // 如果cast失敗,即實際 保存的并非ValueType型數據,則拋出一個異常。

            if(!result)

            throw bad_any_cast(); // 派生自std::bad_cast

            return *result;

            }

             

            any_cast針對指針的版本是這樣:

             

            template<typename ValueType>

            ValueType * any_cast(any * operand)

            {

              // 這個類型檢查很重要,后面會對它作更詳細的解釋

            return

            operand &&

            (operand->type()==typeid(ValueType)) ? // #1

            &static_cast<any::holder<ValueType>*>(operand->content)->held

            : 0; // 這兒有個向下類型轉換

            }

             

             

            這兩個any_cast版本應該很好理解。此外后一個版本中#1處的類型檢查也是必要的,如果沒有這個檢查,考慮以下代碼:

             

            int i=10;

            boost::any anyVal=i;

             

            //如果沒有那個類型檢查,這將通過編譯且運行期通常也不會出錯,但是對d的賦值將會是非常奇怪的情形。

            double d=any_cast<double>(anyVal);

             

            這將通過編譯,且運行期通常竟然也不會出錯,下面我為你解釋為什么會這樣。

             

            boost::anyVal=i;其實將anyVal.content指針指向了一個holder<int>對象(請回顧上面的代碼)。然后any_cast<double>(anyVal)實際上調用了any_cast<>針對指針的重載版本,并將anyVal的地址傳遞過去,也就是轉到#1處,因為調用的是any_cast<double>,所以#1處的代碼被編譯器實例化為:

             

            // #2

            static_cast<any::holder<double> *>(operand->content)->held

             

            但是前面說過,operand->content實際指向的是any::holder<int>,所以這個static_cast非法的,然而事實是:它能通過編譯!原因很簡單: holder<double>placeholder的派生類,而operand->content的類型正是placeholder。從基類指針到派生類指針的轉換被認為是合法的。但這卻釀成大錯,因為表達式#2的類型將因此被推導為double!原先holder<int>只給int held;成員分配了sizeof(int)個字節的內存,而現在卻要將int型的held當作double型來使用,也就是說使用sizeof(double)個字節內存。所以這就相當于:

             

            int i=10;

            double* pd=(double*)(void*)&i;

             

            // 行為未定義,但通常卻不會出錯,然而隱藏的錯誤更可怕,你得到的d的值幾乎肯定不是你想要的。

            double d=*pd;

             

            使用typeinfo讓我們有可能在運行時發現這種類型不符并及時拋出異常。但有個違反直觀的事情是上面的那行錯誤的代碼仍能通過編譯,并且你也無法阻止它通過編譯,因為holder<int>holder<double>都是placeholder的基類。所以只能期望程序員們清楚自己在做什么,要不然就給他個異常瞧瞧。

             

            使用boost::any實現virtual template成員函數

            如你所知,C++中沒有提供virtual template function。然而有時候你的確會有這種需要,any可以一定程度上滿足這種需要,例如,

             

            class Base

            {

            public:

            virtual void Accept(boost::any anyData)

            {

            ...

            }

            };

            class Derived:public Base

            {

            public:

            virtual void Accept(boost::any anyData)

            {

            ...

            }

            };

             

            這樣的Accept函數能夠接受任意類型的數據,并且是virtual函數。

            目錄(展開《boost源碼剖析》系列文章)

            本文來自:http://blog.csdn.net/pongba/archive/2004/08/24/82811.aspx

            posts - 94, comments - 138, trackbacks - 0, articles - 94

            Copyright © RichardHe

            亚洲中文字幕无码久久综合网| 久久国产欧美日韩精品免费| 色诱久久av| 国产aⅴ激情无码久久| 色综合久久综合中文综合网| 亚洲va久久久噜噜噜久久男同| 国产成人久久精品一区二区三区| 亚洲午夜久久影院| 久久人搡人人玩人妻精品首页 | 一本色道久久HEZYO无码| 色婷婷综合久久久中文字幕| 久久久久人妻一区二区三区 | 奇米综合四色77777久久| 9久久9久久精品| 欧美粉嫩小泬久久久久久久| 性高湖久久久久久久久| 国产激情久久久久影院小草| 欧美熟妇另类久久久久久不卡 | 欧美伊人久久大香线蕉综合| 日本久久久久久中文字幕| 亚洲午夜久久久影院伊人| 久久久无码精品午夜| 久久久久综合网久久| 亚洲AV乱码久久精品蜜桃| 狠狠色丁香久久婷婷综合蜜芽五月 | 久久精品一区二区三区AV| 久久99精品免费一区二区| 国内精品久久久久影院优| 久久精品国产亚洲av麻豆图片| 久久精品一区二区影院| 国产三级精品久久| 狠狠色伊人久久精品综合网| 久久se精品一区二区| www.久久热| 久久精品男人影院| 伊人热人久久中文字幕| 久久精品国产亚洲麻豆| 99热成人精品免费久久| yellow中文字幕久久网| 久久久久久久国产免费看| 久久精品国产亚洲一区二区三区|