C++ 灵活地在字符串、int和double之间转换,用于C++;变异类
我正在实现一个变量类(不使用boost),我想知道如何处理存储字符串、整数或double中的任意一个并通过ToString()、ToInt()或ToDouble()自动将其转换为所需类型的情况 比如说,C++ 灵活地在字符串、int和double之间转换,用于C++;变异类,c++,C++,我正在实现一个变量类(不使用boost),我想知道如何处理存储字符串、整数或double中的任意一个并通过ToString()、ToInt()或ToDouble()自动将其转换为所需类型的情况 比如说, Variant a = 7; cout << "The answer is" + a.ToString() << endl; // should print "The answer is 7" a = "7.4"; double &b = a.ToDouble()
Variant a = 7;
cout << "The answer is" + a.ToString() << endl; // should print "The answer is 7"
a = "7.4";
double &b = a.ToDouble();
b += 1;
cout << a.ToString() << endl; // should print 8.4
变量a=7;
首先,您是否绝对需要通过引用返回?按值返回可能会更容易,因为您可以随时这样做,而无需更改变量对象的内部状态
如果您确实需要通过引用返回,那么您需要有一个有效的内存位置来返回引用。(例如,返回对堆栈对象的引用是不好的,因为当ToXXX()方法返回时,堆栈对象将消失,而该引用将是对无效内存的引用)
实现这一点的简单方法是在Variant对象中包含每种类型的(可变?)成员变量,并设置该成员变量的值,并根据需要返回对该变量的引用。当然,这样做的缺点是,它使您的变量对象与所有可能对象的总和一样大,但如果您不太关心内存使用情况,这可能没什么问题
如果您也关心如何最大限度地减少变体对象的内存使用,那么您可能需要使用一个联合(或等效的联合)。C联合将适用于POD类型,但如果需要包括非POD类型(例如std::string对象),它们就不够了。如果需要,可以使用字节缓冲区(足够大,可以容纳最大的类型),并在必要时使用新的显式析构函数调用,但实现起来有点麻烦
就数据类型的实际转换而言(例如“7”->(int)7->(double)7.0),您只需实现逻辑(可能通过嵌套的switch语句?)就可以为每一对可能的“源”和“目标”执行正确的操作类型。我不认为有任何神奇的方法可以解决这个问题,除非在为您完成转换的地方使用boost功能。如果您希望能够动态进行转换,这是我能想到的唯一方法
class Variant {
enum internaltype {stringtype, inttype, doubletype} curtype;
std::string strdata; //can't be in union
union {
int intdata;
double doubledata;
};
public:
Variant() :curtype(inttype) {}
Variant(const std::string& s) : curtype(stringtype), strdata(s) {}
Variant(int i) : curtype(inttype) {intdata = i;}
Variant(double d) : curtype(doubletype) {doubledata = d;}
std::string& ToString() {
std::stringstream ss;
switch(curtype) {
case inttype:
ss << intdata;
ss >> stringdata;
break;
case doubletype:
ss << doubledata;
ss >> stringdata;
break;
}
curtype = stringtype;
return &strdata;
}
int& ToInt() {/*much the same*/}
double& ToDouble() {/*much the same*/}
};
类变量{
枚举内部类型{stringtype,inttype,doubletype}curtype;
std::string strdata;//不能在并集中
联合{
int intdata;
双重数据;
};
公众:
Variant():curtype(inttype){}
变量(const std::string&s):curtype(stringtype),strdata(s){
变量(inti):curtype(inttype){intdata=i;}
变量(双d):curtype(双d){doubledata=d;}
std::string&ToString(){
std::stringstream-ss;
开关(curtype){
案例类型:
ss>stringdata;
打破
双箱型:
ss>stringdata;
打破
}
curtype=stringtype;
返回和标准数据;
}
int&ToInt(){/*大致相同*/}
double&ToDouble(){/*大致相同*/}
};
这是一个快速而肮脏的实现,它使用作为值持有者而不是自定义类。正如您所看到的,模板可以帮助减少代码量
ToXXX函数更改存储值的基础类型(除非不需要实际转换),然后返回对它的引用。转换是使用来完成的,这可能不完全适合您的目的(根据词法转换的非常严格的条件,如果转换不成功,它将抛出异常)
#包括
#包括
#包括
#包括
类变量
{
任何价值;
公众:
变量(int n):值(n){}
变量(双d):值(d){}
变量(const std::string&s):值{}
Variant(const char*s):值(std::string(s)){}//如果没有这个值,字符串文本将产生歧义
int&ToInt(){return convert();}
double&ToDouble(){return convert();}
std::string&ToString(){return convert();}
私人:
模板
T&convert()
{
如果(typeid(T)!=value.type()){//否则不需要转换
if(typeid(int)=value.type()){
value=boost::词法转换(boost::任意转换(value));
}
else if(typeid(double)=value.type()){
value=boost::词法转换(boost::任意转换(value));
}
else if(typeid(std::string)=value.type()){
value=boost::词法转换(boost::任意转换(value));
}
}
return*boost::any_cast(&value);
}
};
#包括
使用名称空间std;
int main()
{
变量a=7;
cout要实现类似的功能,您需要能够更改存储的类型,因为如果用户通过引用更改变量,他希望更改影响存储的值,因此我将编写如下内容:
class Variant
{
private:
enum StoreType
{
Integer,
Float,
String,
}
store_type;
union
{
int * as_integer;
double * as_double;
std::string * as_string;
}
store_pointer;
// convert to type
void integer_to_double();
void integer_to_string();
void double_to_integer();
void double_to_string();
void string_to_integer();
void string_to_double();
public:
...
int & ToInt()
{
switch (store_type)
{
case Integer: break;
case Double: double_to_integer(); break;
case String: string_to_integer(); break;
}
return * as_integer;
}
...
}
class Variant
{
private:
enum data_type {
...
};
data_type variant_type;
union Data {
char *string;
int integer;
double dbl;
} data;
public:
Variant(const int data);
Variant(const double data);
Variant(const char *data);
// I think that implementation of the constructors should be pretty straight forward.
int ToInt() const;
double ToDouble() const;
std::string ToString() const;
};
根据您的需要,我建议您下载并研究QVariant类的实现。如果这看起来过于复杂,我建议如下:
class Variant
{
private:
enum StoreType
{
Integer,
Float,
String,
}
store_type;
union
{
int * as_integer;
double * as_double;
std::string * as_string;
}
store_pointer;
// convert to type
void integer_to_double();
void integer_to_string();
void double_to_integer();
void double_to_string();
void string_to_integer();
void string_to_double();
public:
...
int & ToInt()
{
switch (store_type)
{
case Integer: break;
case Double: double_to_integer(); break;
case String: string_to_integer(); break;
}
return * as_integer;
}
...
}
class Variant
{
private:
enum data_type {
...
};
data_type variant_type;
union Data {
char *string;
int integer;
double dbl;
} data;
public:
Variant(const int data);
Variant(const double data);
Variant(const char *data);
// I think that implementation of the constructors should be pretty straight forward.
int ToInt() const;
double ToDouble() const;
std::string ToString() const;
};
从这里开始,转换的实现应该很简单
如果您希望它更简单,并且性能不是主要问题,那么可以将存储在变量中的数据转换为字符串,然后在调用to方法时再转换回来
class Variant
{
private:
char data_string[16384];
public:
Variant(const int data);
Variant(const double data);
Variant(const char *data);
// I think that implementation of the constructors should be pretty straight forward.
int ToInt() const;
double ToDouble() const;
std::string ToString() const;
};
如果您需要转换函数的实现细节,我可以提供它们,但我认为它们应该非常简单。我自己实现了一个简单的变量类(不使用第三方libs)。每个ToXxx
函数都包含一个开关overm\u type
(表示当前持有的类型的枚举)。对于字符串转换(从和到),我使用std::stringstream
。这真的很简单。很像Mooing Duck建议的那样
如果频繁,请注意