前幾天一個(gè)朋友給我看了1段代碼:
any temp; //any is a class
temp = 1;
temp = "a";
temp = x; //x is a abstract class
看到這段代碼著實(shí)下了1跳.初期的感覺(jué)象void*指針那樣,又象variant變量。但感覺(jué)還是比較新穎的,-_-''也許我是菜鳥的原因,在腦袋轉(zhuǎn)了一下后,我實(shí)現(xiàn)了自己的一個(gè)類,用來(lái)接受任何參數(shù),起初我認(rèn)為any應(yīng)該是個(gè)typedef,而接收的類型也是前面知道的(-_-''又沒(méi)弄清需求就去實(shí)現(xiàn)了),所以實(shí)現(xiàn)一個(gè)接收任何參數(shù)的類需要個(gè)typelist,和對(duì)每種類型的泛化,下面是class的定義:
template<typename _typelist>
class?any
{
public:
?typedef typename Loki::TL::TypeAtNonStrict<_typelist,0>::Result?param1;
?typedef typename Loki::TL::TypeAtNonStrict<_typelist,1>::Result?param2;
?typedef typename Loki::TL::TypeAtNonStrict<_typelist,2>::Result?param3;
?typedef typename Loki::TL::TypeAtNonStrict<_typelist,3>::Result?param4;
?typedef typename Loki::TL::TypeAtNonStrict<_typelist,4>::Result?param5;
?any(param1 param):
??m_param1(param){}
?any(param2 param):
??m_param2(param){}
?any(param3 param):
??m_param3(param){}
?any(param4 param):
??m_param4(param){}
?template<typename _Ty>
?const _Ty&??Get()
?{
???? class?CERROR_ACCESS_DENIED;
???? LOKI_STATIC_CHECK((Loki::TL::IndexOf<_typelist,_Ty>::value != -???? 1),CERROR_ACCESS_DENIED);
???? return?__Access<_Ty>();
?}
private:
?template<typename _Ty>
?_Ty&? __Access();
?template<>
?param1& __Access<param1>() {return m_param1;}
?template<>
?param2& __Access<param2>() {return m_param2;}
?template<>
?param3& __Access<param3>() {return m_param3;}
?template<>
?param4& __Access<param4>() {return m_param4;}
?param1??m_param1;
?param2??m_param2;
?param3??m_param3;
?param4??m_param4;
};
typedef any<Loki::TYPE_LIST_3(int,float,char)>?ANY;
這樣似乎就可以接收任何類型了,也可以取出數(shù)據(jù),取出時(shí)必須要知道相應(yīng)的類型,而且,假如類型不在列表里面,則編譯期出錯(cuò)
class?CERROR_ACCESS_DENIED;
LOKI_STATIC_CHECK((Loki::TL::IndexOf<_typelist,_Ty>::value != -???? 1),CERROR_ACCESS_DENIED);
這樣,-_-''似乎就可以了,只要所接收的類型可以拷貝即可。但有個(gè)明了的缺陷,那1就是接收的類型必須編譯期寫死,假如不寫死的話,我個(gè)人開(kāi)始的認(rèn)為是加一個(gè)基類,-_-''
還是要3q我那位朋友,讓我了解到boost::any的用法
下面是boost::any的具體分析,我們要達(dá)到下面幾個(gè)要求:
1:可以接收任何類型的數(shù)據(jù)(具有value屬性)
2: 可以方便的取出數(shù)據(jù)
3:型別安全,不象void*
下面是boost::any的實(shí)現(xiàn),我按部分貼,而且省去我認(rèn)為不重要的東西,因?yàn)樘L(zhǎng)了,這會(huì)影響我blog的收視率。
1:首先來(lái)看下他的構(gòu)造和稀構(gòu)(-_-''錯(cuò)別字)
?any()
????: content(0)
{
}
?
?template<typename ValueType>
?any(const ValueType & value)
????: content(new holder<ValueType>(value))
{
}
?
any(const any & other)
????: content(other.content ? other.content->clone() : 0)
?{
?}
?
?~any()
?{
?????delete content;
?}
從構(gòu)造函數(shù)可以看到,any可以接受默認(rèn)的,任何其他值包括ant本身,在稀構(gòu)里面可以看到對(duì)content的釋放,content在這里是一個(gè)基類的指針,是any內(nèi)部實(shí)現(xiàn)的,我們可以看到,在對(duì)any構(gòu)造是有種方法:
(1)content(new holder<ValueType>(value))
(2)content(other.content ? other.content->clone() : 0)
稍后會(huì)看到holder是派生自content類型的一個(gè)模板實(shí)現(xiàn),也許講到這里,有些應(yīng)該明白了any是怎么保存任何類型的吧,對(duì)于其他any的構(gòu)造,我們發(fā)現(xiàn)調(diào)用了content的一個(gè)clone方法,很明顯這是content的一個(gè)虛方法,這個(gè)方法的存在得以讓我們運(yùn)用虛函數(shù)的機(jī)制正確的拷貝對(duì)象,下面會(huì)看到這只是個(gè)簡(jiǎn)單的new操作。
2:來(lái)看下any的operator =的重載
any & swap(any & rhs)
{
?????std::swap(content, rhs.content);
?????return *this;
}
?
template<typename ValueType>
any & operator=(const ValueType & rhs)
{
????any(rhs).swap(*this);
????return *this;
}
?
any & operator=(const any & rhs)
{
??????any(rhs).swap(*this);
??????return *this;
}
可以看到operator =,接收任何其他類型的參數(shù),swap方法的實(shí)現(xiàn),用來(lái)交換2個(gè)對(duì)象的content指針,我們可以看到operator =里面臨時(shí)對(duì)象的構(gòu)建,在函數(shù)結(jié)束后,自動(dòng)釋放原來(lái)content的對(duì)象,這有點(diǎn)RAII味道。(http://blog.sina.com.cn/u/1019039487)獨(dú)家小菜。。
3:下面來(lái)看下輔助類
?bool empty() const
?{
??????return !content;
?}
?
?const std::type_info & type() const
?{
??????return content ? content->type() : typeid(void);
?}
可以看到。一個(gè)empty,一個(gè)type,很形象。
4:下面來(lái)看下上面content所指的對(duì)象,以及any怎么保存任何類型,以及這種怎么保證型別安全
class placeholder
{
public: // structors
?????virtual ~placeholder()
?????{
?????}
public: // queries
??????virtual const std::type_info & type() const = 0;
??????virtual placeholder * clone() const = 0;
};
?
template<typename ValueType>
class holder : public placeholder
{
public: // structors
?????holder(const ValueType & value)
????????????? : held(value)
?????{
?????}
public: // queries
?????virtual const std::type_info & type() const
?????{
?????????return typeid(ValueType);
?????}
?
?????virtual placeholder * clone() const
?????{
??????????return new holder(held);
?????}
public: // representation
?????ValueType held;
};(-_-''格式矯正真是類啊)
?
placeholder就是上面content指向的對(duì)象,可以看到他定義的一些提供給any調(diào)用的函數(shù)和虛基本必須的虛稀構(gòu)函數(shù)(可以看到any對(duì)content調(diào)用了delete)
下面是holder的實(shí)現(xiàn),holder是一個(gè)模板,里面定義的
ValueType held;
很明星是any用來(lái)保存任何類型的,回顧下上面所說(shuō)的any初始化content的2種方法
(1)content(new holder<ValueType>(value))
(2)content(other.content ? other.content->clone() : 0)
從這個(gè)地方可以看到怎么初始化holder對(duì)象,并保存到content.注意到這里的held是public的,這樣就提供了對(duì)數(shù)據(jù)訪問(wèn)的功能,在訪問(wèn)的時(shí)候必須要知道具體要訪問(wèn)的類型,才能調(diào)用相應(yīng)的static_cast或者dynamic_cast來(lái)操作,而這樣其實(shí)也提供了型別安全的保證,eg:不象malloc,返回void*,然后()轉(zhuǎn)換一下。
5:看下怎么訪問(wèn)any里面的屬性值:這里就不列舉出所有的實(shí)現(xiàn),因?yàn)橛行┦菍?duì)const的版本。
template<typename ValueType>
ValueType * any_cast(any * operand)
{
????return operand && operand->type() == typeid(ValueType)
??????????????????? ? &static_cast<any::holder<ValueType> *>? (operand->content)->held
??????????????????? : 0;
}
?
template<typename ValueType>
ValueType any_cast(const any & operand)
{
?????typedef BOOST_DEDUCED_TYPENAME??????? remove_reference<ValueType>::type nonref;
?
???const nonref * result = any_cast<nonref>(&operand);
???if(!result)
??????????? boost::throw_exception(bad_any_cast());
????return *result;
}//這里去掉1些原來(lái)實(shí)現(xiàn)的代碼和注釋
可以看到具體的實(shí)現(xiàn)方式&dynamic_cast的邏輯差不多,對(duì)引用的cast有可能拋出異常。通過(guò)上面這種方式,就達(dá)到了對(duì)數(shù)據(jù)的讀取,讀取時(shí)必須知道里面的數(shù)據(jù)類型。可以看出any只能保存一個(gè)值,-_-''不向我那個(gè),可以同時(shí)保存不同類型的值。
6:extension
可以通過(guò)std::vector<boost::any> anys,來(lái)構(gòu)建一個(gè)任何類型的列表,但訪問(wèn)比較麻煩。
也可以通過(guò)any來(lái)達(dá)到虛函數(shù)不能為template的限制(因?yàn)橐粋€(gè)是靜態(tài)的一個(gè)是動(dòng)態(tài)的)
象下面:
class CBase
{
?public:
???? virtual void Set(boost::any) = 0;
};
?
class CHild:
???? public CBase
{
?public:
???? virtual void Set(boost::any param)
???? {
????????? m_value = param;
???? }
?private:
???? boost::any? m_value;
};
?
CHild?test;
CBase* ptr = &test;
ptr->Set(1);
ptr->Set('a');
7.finish...總算完成了...-_-''要變唐僧了...