如何从一个函数返回不同的类?

sky*_*oor 11 c++

我有一个问题,但它不仅限于C++.如何从一个函数返回完全不同的类?

f() {

in case one: return A;
in case two: return B;
in case three: return C;


}
Run Code Online (Sandbox Code Playgroud)

例如,我在空间中有两个球,根据位置和大小,两个球相互交叉有三种情况,即非交点,点,a和圆.如何在一个函数中返回不同的类?

谢谢.

Man*_*uel 30

如果你能买得起Boost,那么这听起来就像是Boost.Variant的完美应用.

struct NoIntersection {
    // empty
};
struct Point { 
    // whatever
};
struct Circle { 
    // whatever
};

typedef boost::variant<NoIntersection, Point, Circle> IntersectionResult;

IntersectionResult intersection_test() {

    if(some_condition){ 
        return NoIntersection();
    }
    if(other_condition){ 
        return Point(x, y);
    }
    if(another_condition){ 
        return Circle(c, r);
    }
    throw std::runtime_error("unexpected");
}
Run Code Online (Sandbox Code Playgroud)

然后,您使用静态访问者处理结果:

 struct process_result_visitor : public boost::static_visitor<> {

     void operator()(NoIntersection) {
        std::cout << "there was no intersection\n";
     }
     void operator()(Point const &pnt) {
        std::cout << "there was a point intersection\n";
     }
     void operator()(Circle const &circle) {
        std::cout << "there was a circle intersection\n";
     }
 };

 IntersectionResult result = intersection_test();
 boost::apply_visitor(process_result_visitor(), result);
Run Code Online (Sandbox Code Playgroud)

编辑:访客类必须来自boost::static_visitor

更新:在一些批评意见的提示下,我写了一些基准程序.比较了四种方法:

  • boost::variant
  • 联盟
  • 类层次结构
  • boost::any

当我使用默认优化(VC08)在发布模式下编译时,这些是我的家用计算机中的结果:

使用boost :: variant进行测试需要0.011微秒

用union测试需要0.012微秒

用层次结构测试花了0.227微秒

使用boost :: any测试需要0.188微秒

使用boost::variant比联合更快并且引导(IMO)到最优雅的代码.我猜测类层次结构方法的极差性能是由于需要使用动态内存分配和动态调度.boost::any既不快也不优雅,所以我不会考虑这个任务(它有其他应用程序)

  • @ e.tadeu - 为了回应你的批评,我更新了我的答案.希望能让你重新考虑对Boost.Variant的立场. (4认同)
  • +1.如果您不处理其中一个案例,则访问者结构具有无法编译的额外好处. (2认同)

ant*_*res 13

要返回的类应该从公共基类派生.因此,您可以返回基本类型.例如(这不是代码,只是标记模式,如果您的语言支持此抽象或抽象类,则可以使用接口.如果使用C++,则必须返回公共类的指针):

class A : public Common
{
..
}

class B : public Common
{
..
}

class C : public Common
{
..
}

Common f() {

in case one: return A;
in case two: return B;
in case three: return C;


}
Run Code Online (Sandbox Code Playgroud)

  • @skydoor至少可以说那是糟糕的设计. (13认同)
  • 请注意,在C++中,您需要将*指针*返回到基类型. (9认同)
  • 如果它们完全无关,你就写了一个非常奇怪的功能.很奇怪,你的许多同行会认为你的设计是错误的,甚至是直言不讳,只是完全错误. (2认同)

Ale*_*tov 6

除了@Manuel的Boost.Variant建议之外,请看看Boost.Any:具有与Boost.Variant类似的目的,但有不同的权衡和功能.

boost :: any是无界的(可以包含任何类型),而boost :: variant是有界的(支持的类型以变体类型编码,因此它只能包含这些类型的值).

// from Beyond the C++ Standard Library: An Introduction to Boost 
// By Björn Karlsson 

#include <iostream>
#include <string>
#include <utility>
#include <vector>
#include "boost/any.hpp"

class A {
public:
  void some_function() { std::cout << "A::some_function()\n"; }
};

class B {
public:
  void some_function() { std::cout << "B::some_function()\n"; }
};

class C {
public:
  void some_function() { std::cout << "C::some_function()\n"; }
};

int main() {
  std::cout << "Example of using any.\n\n";

  std::vector<boost::any> store_anything;

  store_anything.push_back(A());
  store_anything.push_back(B());
  store_anything.push_back(C());

  // While we're at it, let's add a few other things as well
  store_anything.push_back(std::string("This is fantastic! "));
  store_anything.push_back(3);
  store_anything.push_back(std::make_pair(true, 7.92));

  void print_any(boost::any& a);
  // Defined later; reports on the value in a

  std::for_each(
    store_anything.begin(),
    store_anything.end(),
    print_any);
}

void print_any(boost::any& a) {
  if (A* pA=boost::any_cast<A>(&a)) {
    pA->some_function();
  }
  else if (B* pB=boost::any_cast<B>(&a)) {
    pB->some_function();
  }
  else if (C* pC=boost::any_cast<C>(&a)) {
    pC->some_function();
  }
}
Run Code Online (Sandbox Code Playgroud)