我可以使用相同的方法返回不同的对象,具体取决于它在C ++中的输入吗?

时间:2017-04-03 14:35:59

标签: c++ parsing unions

我想创建一个基本的解析方法,它使用C ++作为输入vector <uint8_>。根据单个字节的实际值,此方法应返回表示此数据的结构。

例如:

输入1:{0x10, 0x02, 0x03}
输入2 {0x20, 0x05, 0x02}

第一个字节应表示对象的类型,其中0x10 = cube,0x20 = sphere 第二个字节取决于立方体的宽度或球体的直径的类型 第三个字节是立方体的体积或球体的质量。

我可以创建一个方法来获取输入向量并根据此向量中的值返回这两个不同结构中的一个:

struct cube
{
    int width;
    int volume;
};

struct sphere
{
    int diameter;
    int mass;
};

4 个答案:

答案 0 :(得分:1)

为了从函数返回不同的类型,类型必须相关(见下文)。此外,返回类型必须是指针或智能指针。

如果您希望将不相关类型的数据传回呼叫者,您有两种选择:

  • 将参考参数添加到每种可能类型的struct
  • 接受一个接受每种可能类型元素的回调。

第一种方法:

enum shape_t {Cube, Sphere};
shape_t parse(vector<uint8_t> data, cube &c, sphere& s) {
    if (<data represents a cube>) {
        c.width = ...
        c.volume = ...
        return Cube; 
    } else if (<data represents a sphere>) {
        s.diameter = ...
        s.mass = ...
        return Sphere;
    } else {
        ... // Handle error
    }
}

第二种方法:

struct parse_callback {
    virtual void cube(const cube& c);
    virtual void sphere(const sphere& s);
};
...
void parse(vector<uint8_t> data, parse_callback& cb) {
    ...
    if (<data represents a cube>) {
        cube c;
        c.width = ...
        c.volume = ...
        cb.cube(c); 
    } else if (<data represents a sphere>) {
        sphere s;
        s.diameter = ...
        s.mass = ...
        cb.sphere(s);
    }
}

如果你不介意让你的类从公共库继承,你可以返回一个指向多态类型的智能指针:

enum shape_kind {Cube, Sphere};

struct shape {
    virtual ~shape() {}
    virtual shape_kind kind() = 0;
};

struct cube : public shape {
    shape_kind kind() { return Cube; }
};
struct sphere : public shape {
    shape_kind kind() { return Sphere; }
};

shared_ptr<shape> parse(const vector<uint8_t> data) {
    if (<data represents a cube>) {
        return shared_ptr<shape>(new cube);
    } else {
        return shared_ptr<shape>(new sphere);
    }
}

Demo.

答案 1 :(得分:0)

void find_struct(矢量输入,立方体&amp; c1,球体和sp1) {

if ( input[0] == 0x10 )
{
    c1.width = input[1];
    c1.volume = input[2];
}
else if (input[0] == 0x20)
{
    sp1.diameter = input[1];
    sp1.mass = input[2];
}

}

int main() {

vector <unsigned int> input1 = { 0x10, 0x02, 0x03 };
vector <unsigned int> input2 = { 0x20, 0x05, 0x02 };

cube c1;
c1.volume = 0;
c1.width = 0;

sphere s1;
s1.diameter = 0;
s1.mass = 0;

find_struct(input1,c1,s1);

if (c1.volume != 0)
{
    std::cout << "cube is returned" << std::endl;
}
if (s1.diameter != 0)
{
    std::cout << "sphere is returned" << std::endl;
}

}

作为替代方案,将struct member 0指定为默认值。

然后将cube和sphere实例发送到函数 find_struct , 此函数返回修改后的 c1 ans sp1

检查结构值是否为零!!!!

答案 2 :(得分:0)

只是为了保持简单并且仍然正确我认为最好保持m.antkowicz建议的方法并返回指向基础对象的指针以提供多态行为:

struct shape {
    //...
};

struct cube: shape { };
struct sphere: shape { };

// ---

shape* foo(vector<uint8_> v) {
    //...
}

通过这种方式,您的方法将能够返回球体或立方体,甚至可以在将来轻松添加新形状而不会发生重大变化。

当然,不是返回一个简单的形状指针(shape*),它可能是一个智能指针std::shared_ptr<shape>但是现在我发现重要的是保持答案简单并专注于实际的解决方案

答案 3 :(得分:0)

这是一个基于联合的提议,具有强烈的C风格,即小物体方向 (OP邀请工会提出建议,我想工会经常引用的风险不是为了讨论这个问题。)
主要设计方案是使用联合。

更新:使用返回值更改为API。

我添加了演示器代码,显示了使用变量内部可用信息进行错误处理和检测形状类型的可能性。
我相信任何客户端代码(处理解析器的结果)都需要找出里面的形状。设计一个可以使用单一数据类型的API是不够的 我推测(不要因缺乏信息而责怪OP)如果可以调用客户端代码的不同部分,每个部分都隐含地知道它接收的形状类型,
那么就没有必要找到一种数据设计来承载一种类型的所有形状。

typedef enum tenCubeOrSphere_tag
{
    nenInvalid   = 0x0,
    nenCube      = 0x10,
    nenSphere    = 0x20
} tenCubeOrSphere;

typedef struct tstCube_tag
{
    tenCubeOrSphere enWhich;
    // Note that this is the same for cube and for sphere

    int width;
    int volume;
} tstCube;

typedef struct tstSphere_tag
{
    tenCubeOrSphere enWhich;
    // Note that this is the same for cube and for sphere

    int diameter;
    int mass;
} tstSphere;

typedef union tunShape_tag
{
    tstCube   Cube;
    tstSphere Sphere;
    tstCube   Unknown;
    /* just for selfexplaining client code,
       could also be tstSphere, same thing */
} tunShape;

// That's it, below is just demonstrator code.

tunShape parse(/* assume here an input parameter,
               a reference to parseable vector */)
{   tunShape Out;

    { /* parsing happens here,
         assume it finds a cube */
         Out.Cube.enWhich=nenCube;
         Out.Cube.volume = /* let's say ... */   5;
         Out.Cube.width  = /* hmm...        */ 125;

      /* in case of sphere */
         Out.Sphere.enWhich =nenSphere;
         Out.Sphere.diameter= /* let's say ... */ 30;
         Out.Sphere.mass    = /* hmm...        */ 14000;
    }

    return Out;
}

void client (void)
{   tunShape unReceiver;
    unReceiver = parse(/* iput vector */);
    if        (unReceiver.Unknown.enWhich == nenInvalid)
    {/* error handling */
    } else if (unReceiver.Unknown.enWhich == nenCube)
    {   std::cout << "It is a cube: "   << unReceiver.Cube.volume << "," << unReceiver.Cube.width << std::endl;
    } else /* obviously a sphere */
    {   std::cout << "It is a sphere: " << unReceiver.Sphere.mass << "," << unReceiver.Sphere.diameter << std::endl;
    }
}