2017-07-02 64 views
0

对于noob问题抱歉,但我似乎无法摆脱C++的静态性质。问题:我有一个返回一个枚举的类,根据它我必须使用另一个类来转换所述类并返回一个向量。在代码:取决于枚举的函数超载

enum TYPES { TYPE_A, TYPE_B, TYPE C } 

class A { 
    TYPES getType() {} 
} 
class B : public A {} 
class C : public A {} 
class D : public A {} 

std::vector<?> convert_to_vector(const A& a) { 
    // depending on what enum is returned by a.getType() 
    // I have to convert a into B, C, or D class and return std::vector of 
    // an appropriate type, e.g. int for B, float for C, etc. 
} 

int main() { 
    A a; 
    auto v = convert_to_vector(a); 
} 

最简单的方法将使用switch(a.getType())但我在各种情况下具有不同的返回类型和使用auto返回类型不起作用。我已经尝试过模板和模板规范,但他们不接受由a.getType()返回的运行时变量。我想在这里我必须有一些简单的解决方案,但我在这一点上已经没有想法,并且会很感激任何指针。

谢谢!

+2

你想用这个解决方案解决什么问题?你不能使用虚函数,多态性和指向基类的指针吗?一般来说,打开“类型”往往是一个糟糕的设计的标志。 –

+0

那么,我正在使用一个库给我所有的类和枚举。正如我所说的,基类“A”通过该函数只告诉我它的类型,我必须将它转换为派生类来获取向量所需的数据。我想创建一个由enum专门开发的派生类,但C++不是我的母语,我很快就迷失在模板中。 – maga

回答

2

您不能在运行时更改C++函数的返回类型。但是你可以使用一个variant类型:

std::variant<std::vector<int>, std::vector<float>> convert_to_vector(const A& a) { 
    if (a.getType() == TYPE_B) 
     return std::vector<int>(); 
    if (a.getType() == TYPE_C) 
     return std::vector<float>(); 
    throw std::logic_error("unsupported type"); 
} 

如果你没有C++ 17,你可以用boost::variant而不是std::variant

1

我认为,而不是决定一个枚举上的向量的类型一个更好的解决方案将是有一个父母class A其中可以有一个向量内的基于模板变量。在您的课程B, C, D中,您可以简单地继承A并指定模板类型。所以,当你为B, C, D创建一个新对象时,你已经有了这些对象的向量成员。你也可以有一个虚拟函数convertToVec,你可以在子类中重写,这取决于你想如何将数据转换成矢量。

template<class T> 
class A { 
    std::vector<T> vec; 
    std::vector<T> GetVector() { return vec; } 
    virtual convertToVec() { .... } 
} 
class B : public A<bool> {} 
class C : public A<float> {} 
class D : public A<long long int> {} 

int main() { 
    B b; 
    b.GetVector(); 
    //A* b = new B(); 
    //b->convertToVec(); 
} 
1

虽然这是相当困难的遵循究竟你正在努力实现在这里,将使用switch-case是不是一个好主意,而不是你最好充分利用多态性。例如:

class A { 
    public: 
     virtual void convertToVector(AuxVectorConverter& aux) = 0; 
}; 

class B { 
    public: 
     // Add here specific implementation 
     virtual void convertToVector(AuxVectorConverter& aux) { 
      aux.convertToVectorB(this); 
     } 
}; 

class C { 
    public: 
     // Add here specific implementation 
     virtual void convertToVector(AuxVectorConverter& aux) { 
      aux.doSomethingC(this); 
     } 
}; 

// Aux class 
class AuxVectorConverter { 
    public: 
     convertToVector(A* a) { 
      a->convertToVector(this); 
     } 

     convertToVectorB(B* b) { 
      // Do code specific for B 
     } 

     convertToVectorC(C* c) { 
      // Do code specific for B 
     } 
} 

int main() { 
    AuxVectorConverter* aux; 

    A* a = ...; // Initialize here either with instance of B or C 

    // Now, based on run time aux class will issue appropriate method. 
    aux.convertToVector(a); 
} 

您可能会发现更多的细节here


UPDATE(基于评论)

另一种做法可能是从TYPES定义地图的一些抽象类,将与上面的模式对齐,例如:

​​

而且动作的定义与我上面显示的层次非常相似,例如,

class AbstractAction { 
    public: 
     virtual void convertToVector(AuxVectorConverter& aux) = 0; 
}; 

class ActionB: public AbstractAction { 
    public: 
     virtual void convertToVector(AuxVectorConverter& aux) { 
      aux.covertToVectorB(this); 
     } 
}; 
+0

我从另一个库中获取所有这些类,除非创建派生类,否则我无法扩展它们。但这不是问题,问题是我的函数得到了对'A'类的实例的引用,我不知道应该将哪个类转换为它,除非我运行'getType'函数。所以我不得不求助于切换,在你的场景中,我必须用B或C实例初始化'A * a',但要知道哪一个我必须打开'getType'。至少这就是我迄今为止对你的代码的理解。那是对的吗? – maga

+1

好的,如果你对班级没有控制权,你仍然可以将它们包装到你的层次结构中或装饰它们。 –