01.#include <iostream>
02.#include <list>
03.#include <boost/any.hpp>
04.
05.typedef std::list<boost::any> list_any;
06.
07.//關鍵部分:可以存放任意類型的對象
08.void fill_list(list_any& la)
09.{
10. la.push_back(10);//存放常數
11. la.push_back( std::string("dyunze") );//存放字符串對象;注意la.push_back(“dyunze”)錯誤,因為會被當錯字符串數組
12.}
13.
14.//根據類型進行顯示
15.void show_list(list_any& la)
16.{
17. list_any::iterator it;
18. boost::any anyone;
19.
20. for( it = la.begin(); it != la.end(); it++ )
21. {
22. anyone = *it;
23.
24. if( anyone.type() == typeid(int) )
25. std::cout<<boost::any_cast<int>(*it)<<std::endl;
26. else if( anyone.type() == typeid(std::string) )
27. std::cout<<boost::any_cast<std::string>(*it).c_str()<<std::endl;
28. }
29.}
30.
31.int main()
32.{
33. list_any la;
34. fill_list(la);
35. show_list(la);
36.
37. return 0;
38.}
#include <iostream>
#include <list>
#include <boost/any.hpp>
typedef std::list<boost::any> list_any;
//關鍵部分:可以存放任意類型的對象
void fill_list(list_any& la)
{
la.push_back(10);//存放常數
la.push_back( std::string("dyunze") );//存放字符串對象;注意la.push_back(“dyunze”)錯誤,因為會被當錯字符串數組
}
//根據類型進行顯示
void show_list(list_any& la)
{
list_any::iterator it;
boost::any anyone;
for( it = la.begin(); it != la.end(); it++ )
{
anyone = *it;
if( anyone.type() == typeid(int) )
std::cout<<boost::any_cast<int>(*it)<<std::endl;
else if( anyone.type() == typeid(std::string) )
std::cout<<boost::any_cast<std::string>(*it).c_str()<<std::endl;
}
}
int main()
{
list_any la;
fill_list(la);
show_list(la);
return 0;
}
boost::any的優點:
對設計模式理解的朋友都會知道合成模式。因為多態只有在使用指針或引用的情況下才能顯現,所以std容器中只能存放指針或引用(但實際上只能存放指針,無法存放引用,這個好像是c++的不足吧)。如:
std::list<BaseClass*> mylist;
這樣,我們就要對指針所指向內容的生存周期操心(可能需要程序員適時刪除申請的內存;但是由于存放指針,插入/刪除的效率高),而使用boost::any就可能避免這種情況,因為我們可以存放類型本身(當然存放指針也可以)。這是boost::any的優點之一。
boost::any另一個優點是可以存放任何類型。而前面提到的mylist只能存放BaseClass類指針以及其繼承類的指針。
boost::any的缺點:
由于boost::any可以存放任何類型,自然它用不了多態特性,沒有統一的接口,所以在獲取容器中的元素時需要實現判別元素的真正類型,這增加了程序員的負擔。與面向對象編程思想有些矛盾,但整個標準c++模板庫何嘗不是如此,用那些牛人的話來說,是“有益補充”。
總之,有利必有弊,沒有十全十美的。
分析并模仿boost::any:
讀了一下boost::any的源代碼,并模仿一下其實現(相當一部分時拷貝原代碼),下面是代碼(只包含必要功能)。
實現any的功能主要由三部分組成:
1)any類
2)真正保存數據的holder類及其基類placeholder
3)獲取真正數據的模板函數any_cast,類型轉換的功能。
view plaincopy to clipboardprint?
01.#include <iostream>
02.#include <list>
03.#include <cassert>
04.
05.//自定義的any類
06.class any
07.{
08.public:
09.
10. //保存真正數據的接口類
11. class placeholder
12. {
13. public:
14. virtual ~placeholder()
15. {
16. }
17. public:
18.
19. virtual const std::type_info & type() const = 0;
20. virtual placeholder * clone() const = 0;
21. };
22.
23. //真正保存和獲取數據的類。
24. template<typename ValueType>
25. class holder : public placeholder
26. {
27. public:
28. holder(const ValueType & value): held(value)
29. {
30. }
31.
32. public:
33.
34. virtual const std::type_info & type() const
35. {
36. return typeid(ValueType);
37. }
38.
39. virtual placeholder * clone() const
40. {
41. return new holder(held);//使用了原型模式
42. }
43.
44. public:
45.
46. //真正的數據,就保存在這里
47. ValueType held;
48. };
49.
50.public:
51.
52. any(): content(NULL)
53. {
54. }
55.
56. //模板構造函數,參數可以是任意類型,真正的數據保存在content中
57. template<typename ValueType>
58. any(const ValueType & value): content(new holder<ValueType>(value))
59. {
60. }
61.
62. //拷貝構造函數
63. any(const any & other)
64. : content(other.content ? other.content->clone() : 0)
65. {
66. }
67.
68. //析構函數,刪除保存數據的content對象
69. ~any()
70. {
71. if(NULL != content)
72. delete content;
73. }
74.
75.private:
76. //一個placeholde對象指針,指向其子類folder的一個實現
77. // 即content( new holder<ValueType>(value) )語句
78. placeholder* content;
79.
80. template<typename ValueType> friend ValueType any_cast(const any& operand);
81.public:
82.
83. //查詢真實數據的類型。
84. const std::type_info & type() const
85. {
86. return content ? content->type() : typeid(void);
87. }
88.};
89.
90.
91.//獲取content->helder數據的方法。用來獲取真正的數據
92.template<typename ValueType>
93.ValueType any_cast(const any& operand)
94.{
95. assert( operand.type() == typeid(ValueType) );
96. return static_cast<any::holder<ValueType> *>(operand.content)->held;
97.}
98.
99.//下代碼是使用示例
100.
101.typedef std::list<any> list_any;
102.
103.void fill_list(list_any& la)
104.{
105. la.push_back(10);//存放常數;調用了any的模板構造函數,下同
106. la.push_back( std::string("我是string") );//存放字符串對象;注意la.push_back(“dyunze”)錯誤,因為會被當錯字符串數組
107.
108. char* p = "我是常量區字符串abc";
109. la.push_back(p);//可以存放指針,但要注意指針的失效問題
110.}
111.
112.//根據類型進行顯示
113.void show_list(list_any& la)
114.{
115. list_any::iterator it;
116.
117. for( it = la.begin(); it != la.end(); it++ )
118. {
119.
120. if( (*it).type() == typeid(int) )
121. std::cout<<any_cast<int>(*it)<<std::endl;
122. else if( (*it).type() == typeid(std::string) )
123. std::cout<<any_cast<std::string>(*it).c_str()<<std::endl;
124. else if( (*it).type() == typeid(char*) )
125. std::cout<<any_cast<char*>(*it)<<std::endl;
126. }
127.}
128.
129.int main()
130.{
131. list_any la;
132. fill_list(la);
133. show_list(la);
134.
135. return 0;
136.}
boost::any是一個很有趣的類,剛剛開始我還以為其就是一個variant類型,
能夠將任意類型值保存進去,能夠以任意類型值讀出來,不過我錯了 :(
boost::any的作者認為,所謂generic type有三個層面的解釋方法:
1.類似variant類型那樣任意進行類型轉換,可以保存一個(int)5進去,
讀一個(string)"5"出來。Win下面的VARIANT類型是以一個巨大的
union實現的類似功能,使用靈活但效率較低
2.區別對待包含值的類型,保存一個(int)5進去,不會被隱式轉換為
(string)'5'或者(double)5.0,這樣效率較高且類型安全,
不必擔心ambiguous conversions
3.對包含值類型不加區別,例如把所有保存的值強制轉換為void *保存
讀取時再有程序員判斷其類型。這樣效率雖最高但無法保證類型安全
boost::any就選擇了第二層面的設計思路,它允許用戶將任意類型值保存
進一個any類型變量,但內部并不改變值的類型,并提供方法讓用戶在使用時
主動/被動進行類型判斷。
在實現方面,boost::any使用兩層內部類placeholder和holder保存
實際類型的值。類placeholder只是一個接口,模板類holder是特定類型
的實現。其中type()方法獲取實際值類型,即typeid(ValueType);
clone()方法獲取值的拷貝return new holder(held);
virtual const std::type_info & type() const
virtual placeholder * clone() const
其值的類型信息不象Win的VARIANT那樣以專門的字段保存,
而是通過模板參數形式靜態保存。這樣效率更高(僅在編譯期),
通用性更強(任何類型都可以,真正any)但靈活性不如VARIANT
在進行拷貝構造/賦值/swap時,都直接將整個placeholder換掉,
這樣可以保證值類型的延續性。
在使用方面,提供了主動/被動進行類型檢測的方法。
可以使用any::type()方法主動檢測值類型
bool is_int(const boost::any & operand)
{
return operand.type() == typeid(int);
}
也可以通過any_cast函數被動進行檢測。此函數與C++中的*_cast
系列關鍵字有相同的語法規范,嘗試進行類型轉換,如類型不匹配則對
指針轉換返回NULL,對引用轉換拋出boost::bad_any_cast異常
boost::any str = string("12345");
try
{
cout << boost::any_cast<int>(str) << endl;
}
catch(boost::bad_any_cast e)
{
cerr << e.what() << endl;
}
在應用方面,any類型適合于類型不同但使用相關的值。如C++的...
形式的函數參數本事不是類型安全的,可以通過vector<any>改造之
然后在使用時檢測類型是否匹配,如可改造printf為
void safe_printf(const char *format, const vector<any>& params)
{
int index = 0;
for(const char *pch = format; *pch; pch++)
{
switch(*pch)
{
case '%':
{
switch(*++pch)
{
case 'i':
case 'd':
{
if(params[index].type() == typeid(int) ||
params[index].type() == typeid(short))
{
...
}
else
throw ...
}
}
}
case '\':
{
...
}
default:
{
putchar(*pch);
}
}
}
}
附:boost::any.hpp
#ifndef BOOST_ANY_INCLUDED
#define BOOST_ANY_INCLUDED
// what: variant type boost::any
// who: contributed by Kevlin Henney,
// with features contributed and bugs found by
// Ed Brey, Mark Rodgers, Peter Dimov, and James Curran
// when: July 2001
// where: tested with BCC 5.5, MSVC 6.0, and g++ 2.95
#include <algorithm>
#include <typeinfo>
#include "boost/config.hpp"
namespace boost
{
class any
{
public: // structors
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;
}
public: // modifiers
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;
}
public: // queries
bool empty() const
{
return !content;
}
const std::type_info & type() const
{
return content ? content->type() : typeid(void);
}
#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
private: // types
#else
public: // types (public so any_cast can be non-friend)
#endif
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;
};
#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
private: // representation
template<typename ValueType>
friend ValueType * any_cast(any *);
#else
public: // representation (public so any_cast can be non-friend)
#endif
placeholder * content;
};
class bad_any_cast : public std::bad_cast
{
public:
virtual const char * what() const throw()
{
return "boost::bad_any_cast: "
"failed conversion using boost::any_cast";
}
};
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>
const ValueType * any_cast(const any * operand)
{
return any_cast<ValueType>(const_cast<any *>(operand));
}
template<typename ValueType>
ValueType any_cast(const any & operand)
{
const ValueType * result = any_cast<ValueType>(&operand);
if(!result)
throw bad_any_cast();
return *result;
}
}
// Copyright Kevlin Henney, 2000, 2001, 2002. All rights reserved.
//
// Permission to use, copy, modify, and distribute this software for any
// purpose is hereby granted without fee, provided that this copyright and
// permissions notice appear in all copies and derivatives.
//
// This software is provided "as is" without express or implied warranty.
#endif
posted on 2011-06-16 18:32
小果子 閱讀(858)
評論(0) 編輯 收藏 引用 所屬分類:
C++