How to set up virtual "get" methods?

D

Duck Dodgers

Here is my situation

class base {
};

class child1 {
int data;
};

class child2 {
string data;
};

I want to access data from a base& object. Now, I know I can't do this
directly, but is there any way I could define a virtual "get" method
that could be called on a base& or base* object and return the correct
type?

I've tried declaring a get method in the base class and overriding it
in the child classes, but that gives an error as expected. I can't see
any way to use polymorphism because the return types must differ.
 
B

BigBrian

This is a decision that needs to be made at compile time, otherwise how
would you know what type of variable to which assign the "get()". That
is, if get() returned both int and string you need to know at compile
time whether to do this

int x = object.get();

or

string x object.get();

Compile time stuff is done with templates, so there's probably a way to
do this with templates, but you need to ask yourself why you're needing
such a thing and decide whether or not it's good design.
 
E

eed132

[Grr... Google needs to make Groups work with the back button, at least
in Firefox. I hit a link by accident and lost most of this reply from
the first time I typed it. Anyway...]

The short answer is that you can't do it.

The medium answer is that you probably shouldn't do it. See BigBrian's
reply. If you post the context of what you're doing, we might be able
to help you come up with an alternate solution. (There are a couple
ideas below, after the long answer.) But you probably shouldn't have to
do this.

If you really want to do this, read on. There are a couple possible
solutions to do something sorta along the same lines as what you
want...

The long answer is that you can fake it. Make a union type, e.g.
typedef union { int number; string str; } string_or_int;
and return that. Depending on the type of variable you are storing the
result in, do like my_base_object.get_data().number or
my_base_object.get_data().str.

Actually, a better way is to make a discriminated union. It'll require
more typing because you'll have to define a class, but it's not too
hard. Add a union like above, then add another field that you can set
to indicate whether a number or string is stored in the union. Make a
get_integer() and a get_string() function that check this type before
returning, and throw an exception if the function call doesn't match
the type.

The longest answer is that an even better way is to drop the whole idea
in the first place. If you're going to go the route of the (possibly
discriminated) union, you might as well just put the two functions
right in the base class and do it that way. Something like this:
class base {
public:
virtual int get_child1_data() { throw someException("Class isn't a
child1"); }
virtual string get_child2_data() { throw someException("Class
isn't a child2"); }
}

class child1 {
...
public:
virtual int get_child1_data() { return data; }
}

(This is sorta hackish. There is probably a better way to do the same
idea. Actually, some might say the discriminated union idea is better.)

Another idea is if the string is going to be something like "123" you
could make the get function in child2 convert data to an integer and
return that; then the get function would be an int in each of its
occurances and it would all work out. Or, you could convert child1's
data to a string (so the integer 123 to the string "123") and return
that.


If this is still not flexible enough, perhaps you should consider
another language like Ruby where everything is a an object that derives
from one root and thus you don't have to worry about types in the same
sense as your typical imperative languages like C, C++, Java, C#, etc.,
only what operations (methods) the objects support. I think Smalltalk
would work too.
 
D

Duck Dodgers

Basically what I'm doing is a simple interpreted programming language.
Because several of the operators work for different types, I wanted to
avoid the "obvious" solution with a discriminated union:

if (x.type == type1)
// Call operator for type1
else if (x.type == type2)
// Call operator for type2
else if (x.type == type 3)
// Call operator for type3
....

Polymorphism isn't the right solution as far as I can tell, and
templates are even messier than the long if..else or switch statements
after jumping through hoops to get them to work. I've looked into the
Boost library, but those are very general and complicated classes where
my need is minimal. Using Boost seems like it would be overkill, for
not really enough gain that I can see at present.

What I have works, but it's ugly and would be difficult to extend if I
added new operators or types.
 
T

Thomas Matthews

Duck said:
Basically what I'm doing is a simple interpreted programming language.
Because several of the operators work for different types, I wanted to
avoid the "obvious" solution with a discriminated union:

if (x.type == type1)
// Call operator for type1
else if (x.type == type2)
// Call operator for type2
else if (x.type == type 3)
// Call operator for type3
...

Polymorphism isn't the right solution as far as I can tell, and
templates are even messier than the long if..else or switch statements
after jumping through hoops to get them to work. I've looked into the
Boost library, but those are very general and complicated classes where
my need is minimal. Using Boost seems like it would be overkill, for
not really enough gain that I can see at present.

What I have works, but it's ugly and would be difficult to extend if I
added new operators or types.

Yep, been there, very ugly.

In my case, I want a generic "get_value" method that would return
the value of a {variant} field. The field could be integer, boolean,
string, etc. A record would be a collection of fields.

The solution for simple types is to return the value as a string.
Many types can be converted to an from strings.

Otherwise, you are looking at double dispatch and the Visitor
design pattern.

Most implementations of this dilemma use a generic pointer and
an enumerated value indicating the type of the data:
enum Variant_Type
{
Unknown, integer, string, etc
};

struct Variant
{
Variant_Type type;
void * pointer_to_data;
// or perhaps a union here
};

Probably the best route is the Visitor pattern.
 
S

Siemel Naran

Duck Dodgers said:
class base {
};

class child1 {
int data;
};

class child2 {
string data;
};

I take it child1, child2 are supposed to derive from base.

Best way is to create an abstract base class Variable. From this derive
Integer and String. class base will have a virtual function that returns a
reference to a Variable.

Related to this will be double dispatch. You can look it up on the
internet.

Idea: If you have a function F1 that takes an Integer and an Integer,
create another function that takes a reference to two Variables and calls F1
after doing a static_cast to convert a reference to a Variable to a
reference to an Integer. If you have a function F2 that takes an Integer
and a String, create another function that again takes a reference to two
Variables and calls F2 after doing a static_cast. Store F1 and F2 in a map
along with the concatenation of typeid -- ie. the function related to F1 has
key strcat(typeid(Integer).name(), typeid(Integer).name()), and the function
related to F2 has key strcat(typeid(Integer).name(), typeid(String).name()).

Then create your generic function F that takes a reference to two Variables
and looks up the typeid in the map.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,202
Messages
2,571,055
Members
47,659
Latest member
salragu

Latest Threads

Top