特色源于变化,不变的东西,不灵活的东西,一般会失去光辉,技术也是,如果一个技术容易扩展,那么它是一个好技术
今天介绍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;
}