variable return type in c++ class

2020-04-21 02:01发布

问题:

i have a class with the following structure:

class myClass
{
    private:
        int type;
        classOne objectOne;
        classTwo objectTwo;
    public:
        myClass(classOne object)
        {
            this->objectOne = object;
            this->type = 0;
        }
        myClass(classTwo object)
        {
            this->objectTwo = object;
            this->type = 1;
        }
}

i now want a method returning an object of type classOne if type is 0 and of type classTwo if type is 1. I do not want two methods to achieve this. the classes have different structures.

Is this even possible? Any suggestions are appreciated :)

回答1:

You can use Boost.Variant to do this. A variant can be constructed directly from any value convertible to one of its bounded types. Similarly, a variant can be assigned any value convertible to one of its bounded types. Heres how you could use it in your class:

class myClass
{
    private:
        boost::variant<classOne, classTwo> obj;
    public:
        myClass(classOne object) : obj(object)
        {
        }
        myClass(classTwo object) : obj(object)
        {
        }
};

It also provides a very convenient boost::get to retrieve the value from the variant. You can use that to supply code for each bounded type you have(ie classOne and classTwo). Here is an example:

if (classOne * x = boost::get<classOne>(&obj))
{
    //Code for classOne
}
else if (classTwo * x = boost::get<classTwo>(&obj)
{
    //Code for classTwo
}

However, such code is quite brittle, and without careful attention will likely lead to the introduction of subtle logical errors detectable only at runtime. Thus, real-world use of variant typically demands an access mechanism more robust than get. For this reason, variant supports compile-time checked visitation via apply_visitor. Visitation requires that the programmer explicitly handle (or ignore) each bounded type. Failure to do so results in a compile-time error.

Visitation of a variant requires a visitor object. Like this:

class object_visitor
: public boost::static_visitor<>
{
public:

    void operator()(classOne & x) const
    {
        //Code for classOne
    }

    void operator()(classTwo & x) const
    {
        //Code for classTwo
    }

};

With the implementation of the above visitor, we can then apply it to obj, as seen in the following:

boost::apply_visitor( object_visitor(), obj );


回答2:

Unless the two types are related (in which case you can create a function that will return a pointer/reference to the common ancestor) you cannot do that directly in C++.

C++ is a statically typed language, meaning that the type of every expression must be known at compile time, but you are trying to define a function whose return type depends on runtime values.

Depending on the particular problem to solve, there might be different approaches that you could take, including using type erasure (return a boost::any, boost::variant or your own type-erasure).



回答3:

ClassOne and ClassTwo need to have the same return type then either via inheritance or composition. i.e ClassOne and ClassTwo need to be subclasses of the same super class OR they need to impl the same interface.



回答4:

I am not sure why you would not use templates for your case.

You can have something like below:

template <class ClassType>
class myClass
{
    private:
        int type;
        ClassType object;            
    public:
        myClass(ClassType object_in)
        {
            this->object = object_in;
            /*
                C++ doesn't support reflection so I don't think there 
                is a robust way of doing the following at runtime.
            */
            type = /* Get Type at runtime */;
        }
        /*
            Have another method which return object in a straigtforward way.
        */
};

However, then this become trivial. Any more insight into what your use case is, such that you have to know the type?

Update: If the ClassType is going to be an Object, you can have a const static int TypeID member for the class, which is set at compile time. You can then use it determine the Type at runtime.



回答5:

If they're completely different structures, with no common base then an alternative way you can return them from the same function is to use void*.

However that's bad form in C++, usually indicating a design failure - either use two different functions, or use a common base class.

It's apples and oranges. If you put an apple into an recipe that calls for an orange it won't be the same recipe anymore.



回答6:

The use of type-id is a sign that you need virtual functions for myClass. Even if the other two classes are totally independent, the fact that they are returned by the same function could easily make them inherit a base class. And also you can just return a pair containing class1, class2 and one of them can be null.



回答7:

The first problem is how you will determine the class of which type has been returned. I think it is possible to return a pointer to structure of this type

struct res {
  myClass* c1;
  ClassOne* c2;
} ;

The field of the not chosen class is NULL, the other points to the object.



标签: c++ class