LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   Two return types (https://www.linuxquestions.org/questions/programming-9/two-return-types-519120/)

Ephracis 01-14-2007 04:17 AM

Two return types
 
Hi,

Simple question: if I have a method in a class which will return either type A or type B, how should I do?

I have a list of objects, the objects can be of two types. So when I call at(int) it can return either a pointer to object of type A or a pointer to an object of type B.

EDIT:
To extend it a little bit, is there a way of managing a Vector containing two types? Not a map, but a sort of Vector<typeA or typeB>.

Regards,

dmail 01-14-2007 05:00 AM

There are a couple of approaches to this, the ones I am thinking about could use the following
Boost Any or Boost Variant, yet these would require you to know the type or a way of finding the type. So you could therefore using std::vector<void*> (which is what boost uses for pointer vectors) and cast to the correct type, but I feel this defeats your purpose.

traene 01-14-2007 07:36 AM

Java for instance has the everything is an object aproach. You just return an java.lang.Object
from your method. Maybe these objects have something in common, some common interface or something,
so you can return an (abstract) base type.

dmail 01-14-2007 07:55 AM

Quote:

Originally Posted by traene
Java for instance has the everything is an object aproach. You just return an java.lang.Object
from your method. Maybe these objects have something in common, some common interface or something,
so you can return an (abstract) base type.

This is how the inner workings of boost Any work, yet the types contained with in the "Any" class need not have any relation to each other.

taylor_venable 01-14-2007 09:14 AM

Quote:

Originally Posted by Ephracis
I have a list of objects, the objects can be of two types. So when I call at(int) it can return either a pointer to object of type A or a pointer to an object of type B.

To extend it a little bit, is there a way of managing a Vector containing two types? Not a map, but a sort of Vector<typeA or typeB>.

What language are you using? I'm guessing from your description that it's something like C++ or Java. The cleanest way would be to create an abstract class that both typeA and typeB implement. Then your vector would contain instances of that abstract class. Alternatively, in C++ you could use unions to express multiple possible types as a single one. This isn't nearly as clean or safe in C++ as in languages like Ada or OCaml, but it is possible.

Libra 01-14-2007 09:39 AM

if it's C++, I would do it like this:

Code:

enum {tpA, tpB} retType_t;


void *at(int i, retType_t *tp)
{
  void *fnc;
  ...
  if (...)
  {
    *tp = tpA;
    fnc = A;
  }
  else
  {
    *tp = tpB;
    fnc = B;
  }
  return fnc;
}

In this case, the caller knows by the value tp is set to to what class it has to be casted.

dmail 01-14-2007 10:02 AM

In some situations you could use this, but if the class is in a hierarchy of classes then you could get splicing of data. Ephracis post some more information, it may be a idea to use a design pattern like visitor and thus let the caller call the correct method and get the correct type.

Ephracis 01-14-2007 10:12 AM

I am using C++ and here is how it looks:

I have a DataList which contains a vector of DataGroups and DataItems.
I have a DataGroup which contains a vector of DataGroups and DataItems.
I have a DataItem class.

Look at it as item is a file, group is a directory and list is root.

DataGroup and DataItem both inherits from DataAbstract, but they add a lot of functionality to it.

My object will create a DataList instance and add some groups and items, and within the groups there will be more nested groups and at last the items.. Just like a file tree or something like that, groups in groups, items in groups and everything in one list.

Then, another class will get this DataList and go through it and take different actions if the item is of type DataGroup or DataItem. I am not writing this class, I just export a pointer to my class DataList which this class will then use.

I need a way of just containing and structuring these classes in a simple way and I want DataList and DataGroup to be able to do stuff like add(DataGroup), add(DataItem) and at(int position).

dmail 01-14-2007 10:52 AM

Quote:

Just like a file tree
It sounds very much like a tree, where a item is a node, list and group are trees.
This may sound condescending :) have you tried to think and design it like this.

taylor_venable 01-14-2007 04:00 PM

What's the difference between DataGroup and DataList? Except for the fact that a DataList is expected by the other function.

You can use DataAbstract to store both types into the same vector, like this:
Code:

#include <iostream>
#include <string>
#include <vector>

class DataAbstract {
public:
    virtual std::string get() = 0;
};

class DataGroup : public DataAbstract {
public:
    std::string get() {
        return "I'm a DataGroup.";
    }
};

class DataItem : public DataAbstract {
public:
    std::string get() {
        return "I'm a DataItem.";
    }
};

int main(int argc, char** argv) {
    std::vector<DataAbstract*>* v = new std::vector<DataAbstract*>();
    v->push_back(new DataGroup());
    v->push_back(new DataItem());
    std::cout << "Item 0 says \"" << v->at(0)->get() << "\"\n";
    std::cout << "Item 1 says \"" << v->at(1)->get() << "\"\n";
    if (typeid(*(v->at(0))) == typeid(*(v->at(1)))) {
        std::cout << "They're the same type!\n";
        std::cout << "Both are type " << typeid(*(v->at(0))).name() << ".\n";
    }
    else {
        std::cout << "They're different types!\n";
        std::cout << "Item 0 is of type " << typeid(*(v->at(0))).name() << ".\n";
        std::cout << "Item 1 is of type " << typeid(*(v->at(1))).name() << ".\n";
    }
    return 0;
}

At the end there you can see how to check the dynamic type of the contents of the vector. Note that the name() of a type is implementation defined: with GCC 3.4.3 for example, I see "9DataGroup" and "8DataItem".

Libra 01-15-2007 04:44 AM

If I have more time, I will search more of that. Since I am an old Pascal programmer, I know the concept of "Class Pointers", of which I have noticed that there is an equivalent in C++, too. Since you have identical parent classes, this will work. In Delphi, you have to define

Type TMyClassPointer = class of TMyParentClass;

May be this helps you so far that you can google around it for C++.

Ephracis 01-15-2007 11:57 PM

There isn't much difference between DataList and DataGroup right now, but the thing is that DataList is what the other classes will see and use, and it will act as root.

I was thinking of using QStack to store the items and groups but I need a way of reordering all items and also get the index where an item is located, this seems a little bit complicated with a QStack.

taylor_venable 01-16-2007 06:23 AM

Unless I misunderstand your problem, just make DataList a vector of DataAbstract, then add < and == for DataAbstract (implemented in the children) so you can use <algorithm> functions to sort or search your vector.


All times are GMT -5. The time now is 04:17 PM.