C++ 灵活地在字符串、int和double之间转换,用于C++;变异类

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()

我正在实现一个变量类(不使用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();
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
函数都包含一个
开关
over
m\u type
(表示当前持有的类型的枚举)。对于字符串转换(从和到),我使用
std::stringstream
。这真的很简单。很像Mooing Duck建议的那样

如果频繁,请注意