特色源於變化,不變的東西,不靈活的東西,一般會失去光輝,技術也是,如果一個技術容易擴展,那麼它是一個好技術
今天介紹c++的動態類特性:
在介紹之前,先介紹c++11中的兩個關鍵字,auto和any,
(1)auto
auto可以表示任何類型,是c++11中的一個關鍵字符號,可以使得代碼簡潔,不用關心具體的類型,類型在編譯器編譯的時候決定:
如: auto a = 5; // int
auto b = 5.0f; // float
auto c = 5.0; // double
std::vector<int> name_list;
auto iter = name_list.begin(); // 容器迭代器
std::cout << a << b << c << endl;
特別是容器迭代器,在沒有auto之前,我們只能不厭其煩的這樣定義:std::vector<int>::iterator it = name_list.begin()
(2) any
any 出現在boost中,也是c++11的特徵,與auto相比,any是一個類,有成員函數和屬性,只能通過any_cast<type>來獲得內部的值,而不能像auto一樣直接使用;
值得說明的是,any本身不是模板類,不像模板類一樣,定義的時候需要指明實例化類型,例如:any<int> a;(這樣定義是不對的,因爲any不是模板類),any只有賦值函數和構造函數是template的,所以可以像auto一樣使用, any i = 5;
any的出現讓C++彷彿變成了一種弱類型的動態語言。
動態語言:運行期間才做數據類型檢查的語言,即編譯的時候不知道每一個變量的類型
靜態語言:編譯期間做數據類型檢查的語言,即編譯的時候就知道每一個變量的類型,如C/C++、C#、JAVA
強類型:變量一定是有類型的, 且變量/對象的類型一旦確定, 其類型不再允許更改,如C/C++/Java/C#
弱類型: 變量的類型概念很弱或者沒有類型的概念, 不同變量的類型可以更改. 如php、Ruby
下面開始介紹c++的動態類特:
我們在編寫程序的時候,經常會出現需要擴展的情況,例如:
class CTest
{
public:
CTest(){}
~CTest(){}
public:
int m_a;
int m_b;
};
如果理想的狀態下,這個類不需要添加新的變量,但是大多數時候,我們的程序需要進行修改和添加新的屬性。
例如我們需要給CTest類添加一個新的屬性, int m_c; 以前我一直是這樣添加的。 我也一直在尋找更好的方法。 上次看我同事的代碼,發現他很好的實現了這種添加。 他是在QT中使用
map<QString, QVariant> m_propertys;
來保存屬性。我知道有很多高手會有更好的實現方法。不過這是我最見過最好的實現方式。
這裏我用boost的boost::any來實現。
#include <boost/any.hpp>
#include <iostream>
#include <string>
#include <map>
using std::string;
using std::map;
using boost::any_cast;
#define AttrMap (boost::any_cast<map<int, int>>(propertys.property["C"]))
class CPropertys
{
public:
CPropertys();
~CPropertys(){};
public:
map <string, boost::any> property; //這裏我沒有使用, m_property,
//因爲這樣,訪問者看起來會更舒服些。
};
CPropertys::CPropertys()
{
// ! 這個可以保存字符串變量
property["A"] = (string)"Hello";
// ! 保存整數變量
property["B"] = (int)5;
map<int, int> a;
a[1] = 7;
// ! 保存map變量
property["C"] = (map<int, int>)a;
}
int main()
{
CPropertys propertys;
propertys.property["B"] = 99;
// ! 我們也可以使用函數來實現,查詢和設置,propertys中的map
AttrMap[1] = 199;
std::cout << boost::any_cast<int>(propertys.property["B"]) << std::endl;
getchar();
return 0;
}
#include <boost/any.hpp>
#include <iostream>
#include <string>
#include <map>
using std::string;
using std::map;
using boost::any_cast;
#define AttrMap (boost::any_cast<map<int, int>>(propertys.property["C"]))
class CPropertys
{
public:
CPropertys();
~CPropertys(){};
public:
template <typename T> bool AddNewProperty(const string &stPropertyName, T &anyProperty);
bool RemoveProperty(const string &stPropertyName);
bool IsExistProperty(const string &stPropertyName);
bool GetValue(const string &stPropertyName, boost::any &value);
template <typename T> bool SetValue(const string &stPropertyName, T &anyProperty);
public:
map <string, boost::any> property;
};
CPropertys::CPropertys()
{
property["A"] = (string)"Hello";;
property["B"] = (int)5;
map<int, int> a;
a[1] = 7;
property["C"] = (map<int, int>)a;
}
template <typename T> bool
CPropertys::AddNewProperty(const string &stPropertyName, T &anyProperty)
{
if (IsExistProperty(stPropertyName))
{
return false;
}
else
{
property[stPropertyName] = anyProperty;
}
return true;
}
bool
CPropertys::RemoveProperty(const string &stPropertyName)
{
if (IsExistProperty(stPropertyName))
{
property.erase(stPropertyName);
return true;
}
return false;
}
bool
CPropertys::IsExistProperty(const string &stPropertyName)
{
return (property.find(stPropertyName) != property.end());
}
bool
CPropertys::GetValue(const string &stPropertyName, boost::any &value)
{
if (IsExistProperty(stPropertyName))
{
value = property[stPropertyName];
}
return false;
}
template <typename T> bool
CPropertys::SetValue(const string &stPropertyName, T &anyProperty)
{
property[stPropertyName] = anyProperty;
return true;
}
int main()
{
CPropertys propertys;
//propertys.property["C"];
//map<int, int> &c = boost::any_cast<map<int, int>>(propertys.property["C"]);
//c[1]
AttrMap[10] = 199;
propertys.property["B"] = 99;
std::cout << propertys.IsExistProperty("F") << std::endl;
std::cout << propertys.property.size() << std::endl;
//propertys.property["F"] = 999; //這句也是可以執行的,不過沒有用AddNewProperty函數來的專業
int value = 323;
propertys.AddNewProperty("F", value);
std::cout << propertys.property.size() << std::endl;
std::cout << boost::any_cast<int>(propertys.property["F"])<< std::endl;
boost::any v;
propertys.GetValue("F", v);
std::cout << boost::any_cast<int>(v) << std::endl;
value = 88888;
propertys.SetValue("F", value);
propertys.GetValue("F", v);
std::cout << boost::any_cast<int>(v) << std::endl;
std::cout << boost::any_cast<int>(propertys.property["B"]) << std::endl;
getchar();
return 0;
}