动态调用具有不同 return 类型的同名函数

dynamically call same named function with different return type

我这里有个情况... 我想设计一个工厂,我可以在其中调用具有相同名称且没有参数但 return 不同数据类型的函数。基于 SubClassName 我需要实例化对象。

需要任何设计模式的帮助或指导?

编辑: 一个抽象的伪代码...

class parent{
 public:
  virtual string getName() = 0;
  //some virtual function.. not sure how to design. As the return type is dynamic.
  *** getValue(){}
};
class A : public parent{
  int x;
 public:
  virtual string getName(){ return "A";}
  virtual int getValue(){retun x;}
};
class B : public parent{
  string s;
 public:
  virtual string getName(){ return "B";}
  virtual string getValue(){ return s;}
};

void main(){
  string callingClass = "B";
  parent * arrayPtrs[2];
  arrayPtrs[0] = new A;
  arrayPtrs[1] = new B;

  for (loop through array, through iterator i){
  if(arrayPtrs[i]->getName == callingClass ){
     cout<<arrayPtrs[i]->getValue;
   }
  }
}

在 C++ 中,一个函数一次只能有一个 return 类型,并且您不能动态更改它。
但是 - 正如@mch 所建议的那样 - 您可以使用模板专业化。但请记住,此方法不是 动态 。您的函数将在 编译时间 生成。

如果我正确理解您的问题,也许这会有所帮助。

class MyObject1
{
    //...
};
class MyObject2
{
    //...
};

template<typename T>
struct Factory
{
    constexpr static T gen();
};

template<>
struct Factory<MyObject1>
{
    constexpr static MyObject1 gen()
    {
        return MyObject1(/*... whatever parameters you see fit ...*/);
    }
};

template<>
struct Factory<MyObject2>
{
    constexpr static MyObject2 gen()
    {
        return MyObject2(/*... whatever parameters you see fit ...*/);
    }
};


int main()
{
    auto myObj = Factory<MyObject1>::gen();
    return 0;
}



尽管这种方法对我来说似乎毫无用处。您可以简单地调用所需的构造函数而不是这个。
但话又说回来,我不确定这是不是你想到的。如果我有任何错误,请随时纠正我。我会尽力编辑我的答案。

编辑:
为了也保留虚拟功能,我能想到的唯一方法是类型擦除:请参阅 https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Type_Erasure

我能得到的最接近你要求的是:

#include <iostream>
#include <string>
#include <any>


class parent {
public:
    // you can use this too but I think type checking is more handy
    // see in main function
    /* virtual std::string getName() const = 0; */

    virtual std::any getValue() const = 0;
};
class A : public parent {
public:
    typedef int value_type;

private:
    value_type x;
public:
    A(value_type x) :
        x(x)
    {}

    /* virtual std::string getName() const override { return "A"; } */
    virtual std::any getValue() const override
    { return this->x; }
};
class B : public parent {
public:
    typedef std::string value_type;

private:
    value_type s;

public:
    B(const value_type& s) :
        s(s)
    {}

    /* virtual std::string getName() const override { return "B"; } */
    virtual std::any getValue() const override
    { return this->s; }
};

int main(){
    using callingClass = A;
    parent* arrayPtrs[2];
    arrayPtrs[0] = new A(42);
    arrayPtrs[1] = new B("my string");

    for (unsigned i = 0; i < sizeof(arrayPtrs) / sizeof(parent*); ++i)
    {
        // Note:
        // dynamic cast will return nullptr if $callingClass
        // is not a derived class
        if (dynamic_cast<callingClass*>(arrayPtrs[i]))
            std::cout << std::any_cast<callingClass::value_type>(arrayPtrs[i]->getValue()) << std::endl;
    }


    return 0;
}



我希望这个有所帮助。
请注意,我使用 dynamic_cast 来检查正确的类型。如果您知道更好的解决方案,您也可以使用它。但在这种情况下,我想不出更好的办法。

编辑 2:

#include <iostream>
#include <string>
#include <tuple>


class some
{
    using id = size_t;

    template<typename T>
    struct type { static void id() { } };

    template<typename T>
    static id type_id() { return reinterpret_cast<id>(&type<T>::id); }

    template<typename T>
    using decay = typename std::decay<T>::type;

    template<typename T>
    using none = typename std::enable_if<!std::is_same<some, T>::value>::type;

    struct base
    {
        virtual ~base() { }
        virtual bool is(id) const = 0;
        virtual base *copy() const = 0;
    } *p = nullptr;


    template<typename T>
    struct data : base, std::tuple<T>
    {
        using std::tuple<T>::tuple;

        T       &get()      & { return std::get<0>(*this); }
        T const &get() const& { return std::get<0>(*this); }

        bool is(id i) const override { return i == type_id<T>(); }
        base *copy()  const override { return new data{get()}; }
    };

    template<typename T>
    T &stat() { return static_cast<data<T>&>(*p).get(); }

    template<typename T>
    T const &stat() const { return static_cast<data<T> const&>(*p).get(); }

    template<typename T>
    T &dyn() { return dynamic_cast<data<T>&>(*p).get(); }

    template<typename T>
    T const &dyn() const { return dynamic_cast<data<T> const&>(*p).get(); }

public:
     some() { }
    ~some() { delete p; }

    some(some &&s)      : p{s.p} { s.p = nullptr; }
    some(some const &s) : p{s.p->copy()} { }

    template<typename T, typename U = decay<T>, typename = none<U>>
    some(T &&x) : p{new data<U>{std::forward<T>(x)}} { }

    some &operator=(some s) { swap(*this, s); return *this; }

    friend void swap(some &s, some &r) { std::swap(s.p, r.p); }

    void clear() { delete p; p = nullptr; }

    bool empty() const { return p; }

    template<typename T>
    bool is() const { return p ? p->is(type_id<T>()) : false; }

    template<typename T> T      &&_()     && { return std::move(stat<T>()); }
    template<typename T> T       &_()      & { return stat<T>(); }
    template<typename T> T const &_() const& { return stat<T>(); }

    template<typename T> T      &&cast()     && { return std::move(dyn<T>()); }
    template<typename T> T       &cast()      & { return dyn<T>(); }
    template<typename T> T const &cast() const& { return dyn<T>(); }

    template<typename T> operator T     &&()     && { return std::move(_<T>()); }
    template<typename T> operator T      &()      & { return _<T>(); }
    template<typename T> operator T const&() const& { return _<T>(); }
};


using any = some;


class parent {
public:
    // you can use this too but I think type checking is more handy
    /* virtual std::string getName() const = 0; */

    virtual any getValue() const = 0;
};
class A : public parent {
public:
    typedef int value_type;

private:
    value_type x;
public:
    A(value_type x) :
        x(x)
    {}

    /* virtual std::string getName() const override { return "A"; } */
    virtual any getValue() const override
    { return this->x; }
};
class B : public parent {
public:
    typedef std::string value_type;

private:
    value_type s;

public:
    B(const value_type& s) :
        s(s)
    {}

    /* virtual std::string getName() const override { return "B"; } */
    virtual any getValue() const override
    { return this->s; }
};

int main(){
    using callingClass = A;
    parent* arrayPtrs[2];
    arrayPtrs[0] = new A(42);
    arrayPtrs[1] = new B("my string");

    for (unsigned i = 0; i < sizeof(arrayPtrs) / sizeof(parent*); ++i)
    {
        // Note:
        // dynamic cast will return nullptr if $callingClass
        // is not a derived class
        if (dynamic_cast<callingClass*>(arrayPtrs[i]))
            std::cout << arrayPtrs[i]->getValue()._<callingClass::value_type>() << std::endl;
    }


    return 0;
}

此片段是为了防止您无法使用 C++17 功能,并且基于:
any class