Switching between variable types?

Started by
8 comments, last by Telastyn 19 years, 4 months ago
Couldn't think of a better thread title, what i mean is this: I have a function that is overloaded a few times with different variable/class types as arguments and i need a good way to switch between the types. Right now i do it like this:
switch(type){
case 0:
 myFunction((TYPE0 *)pointer);
 break;
case 1
 myFunction((TYPE1 *)pointer);
 break;
case 2:
 myFunction((TYPE2 *)pointer);
 break;
// etc..
}

// So i wonder if there is something like an array of types or something:

myFunction((type_array[type] *)pointer);

// or maybe the possibility to use a 'type' variable or something:
myFunction((mytype *)pointer);


Is there something like that or do i have to stick with my old way?
Advertisement
Quote:Original post by Tree Penguin
Is there something like that or do i have to stick with my old way?


two alternatives, dynamic polymorphism via type inheritance or static polymorphism via templates.

if your trying to create a factory method then there are other better alternatives to type switching aswell.

EDIT: Actually three alternatives, third being a combination of dynamic & static polymorphism.

[Edited by - snk_kid on November 23, 2004 10:36:17 AM]
I'm not entirely sure what you're trying to accomplish here, could you give a more concrete example?

However, judging just from the type switch it seems like you should make myFunction() a virtual function on the type of pointer.
Having recently reread How To Ask Questions The Smart Way one of the entries seems like it may be appropriate here:
Quote:Describe the goal, not the step

If you are trying to find out how to do something (as opposed to reporting a bug), begin by describing the goal. Only then describe the particular step towards it that you are blocked on.

Often, people who need technical help have a high-level goal in mind and get stuck on what they think is one particular path towards the goal. They come for help with the step, but don't realize that the path is wrong. It can take a lot of effort to get past this.

Stupid:

How do I get the color-picker on the FooDraw program to take a hexadecimal RGB value?
Smart:

I'm trying to replace the color table on an image with values of my choosing. Right now the only way I can see to do this is by editing each table slot, but I can't get FooDraw's color picker to take a hexadecimal RGB value.

The second version of the question is smart. It allows an answer that suggests a tool better suited to the task.


It may be that you do indeed need to do exactly what you are asking, but it may also be that there is a better way entirely. Cutting a problem down for posting on a forum is a good thing, but too much pruning can mean you're no longer dealing with the real problem.

Enigma
choice 1 dynamic polymorphism:

#include <iostream>struct base_type {   virtual void do_foo() const = 0;   virtual ~base_type() {}};struct derived_type : public base_type {    void do_foo() const { std::cout << "derived1\n"; }};struct derived_type2 : public base_type {    void do_foo() const { std::cout << "derived2\n"; }};void do_do_foo(const base_type& b) {   b.do_foo();}int main() {   const derived_type1 d;   const derived_type2 d2;   do_do_foo(d);   do_do_foo(d2);}


choice 2 static polymorphism:

#include <iostream>struct foo {  void do_bar() const { std::cout << "foo\n"; }};struct bar {  void do_bar() const { std::cout << "bar\n"; }};template < typename Type >void do_do_bar(const Type& b) {   b.do_bar();}int main() {   foo f;   bar b;   do_do_bar(f);   do_do_bar(b);}
If all the types are related in an inheritance hierarchy, put myFunction on the base class and make it virtual (or similar).

class Base {    virtual void myFunction();};class TYPE0 : public Base {    virtual void myFunction();};//etc.


So your code example would be replaced with
pointer->myFunction();

If they aren't related in a class hiearchy you can make your classes accept a Visitor object, which performs whatever you would have put in myFunction: (see VisitorPattern)
//derive from this to carry out what myFunction was doingclass Visitor {    virtual void Visit(TYPE0&) const {}    virtual void Visit(TYPE1&) const {}    virtual void Visit(TYPE2&) const {}};//derive all your types from this and implement Acceptclass Visitable {    virtual void Accept(const Visitor&) = 0;};


Usage:
class TYPE0 : public Visitable {    void Accept(const Visitor& visitor) {        visitor.Visit(*this);//magic happens here    }};//etcclass MyFunction : public Visitor {    virtual void Visit(TYPE0&) const;    virtual void Visit(TYPE1&) const;    virtual void Visit(TYPE2&) const;}


Your original code becomes:
MyFunction visitor;pointer->Accept(visitor);


Then you can add 'virtual functions' to the classes by deriving from Visitor instead of modifying the classes themselves.

edit: Thanks moderator[smile]

[Edited by - petewood on November 23, 2004 11:01:05 AM]
Ok, i´ll explain myself a bit better, this is what i am trying to do:

In my application i have classes like Model, Camera, Texture, and more. With several functions the types of the pointers i pass are not important (managing lists, passing data to other components like etc.) so i cast them to type (void *) to avoid one version of the functions for every type i use.

My problem is that in some cases i might need to do something class specific
( in the gui for example when the user wants to edit something,
or i might want to get the 'name' variable of that object which exists in all classes i use )
but i got a (void *) pointer and an integer specifying the classtype.
What i do now is using a switch statement calling seperate functions for every class but as that's still pretty ugly and i still need to add a lot of functions when adding a class i wondered if there is any way to generalize it some more.

I guess i could make an 'Object' class which contains all non class-specific variables and all the switching between classes, but if there's another way i'd like to know it too.

I hope i am clear now, else please say so :).


EDIT: Thanks snk_kid! Thats what i needed (well, not exactly but i can use it instead).
Sounds to me like templates will do exactly what you want:
// a generic function for any objectstemplate <typename TYPE>void subFunction(TYPE object){	object.repaint();}// a specialisation for specific objectstemplate <>void subFunction(Button button){	button.push();}// the main generic function for all objectstemplate <typename TYPE>void genericFunction(TYPE object){	std::string objectName = object.name();	object.moveTo(10, 10);	subFunction(object);}

Now calling genericFunction on a Label object will get the Label's name, move the Label and then repaint the Label, whereas calling genericFunction on a Button object will get the Button's name, move the Button and then push the Button, providing both Label and Button have the required member functions.

To try and put it more in the context you phrased it in:
Quote:In my application i have classes like Model, Camera, Texture, and more. With several functions the types of the pointers i pass are not important (managing lists, passing data to other components like etc.) so i cast them to type (void *) to avoid one version of the functions for every type i use.

The templated approach means you only write one version of the function, but retain type checking and move type-dependant switching from runtime to compiletime.

Quote:My problem is that in some cases i might need to do something class specific
( in the gui for example when the user wants to edit something,
or i might want to get the 'name' variable of that object which exists in all classes i use )
but i got a (void *) pointer and an integer specifying the classtype.

Break the specialised cases out into seperate functions and write template specialisations for them. It requires almost no extra code (just writing template a few times) and retains type checking and often makes the function clearer.

Quote:What i do now is using a switch statement calling seperate functions for every class but as that's still pretty ugly and i still need to add a lot of functions when adding a class i wondered if there is any way to generalize it some more.

Hopefully what I've shown is applicable. Templates are there for generalisation. They are after all Generic Programming.

Hope that helps,

Enigma
In short: learn C++. And before you say "but I know" - you're coding in C. Looks like you know your C pretty well, too. A good place to start is Bruce Eckel's "Thinking in C++" - its a free PDF available online.
-- Single player is masturbation.
I actually had almost the same exact implimentation, problem and solution 2-3 months ago. [though I put the switch statement in the function rather than before the function call]

I went with virtual inheritance for most cases, as [iirc] templates don't play nice with void pointers, requiring you to do the casting anyways. There still are a few places where the switch(type){} junk exists, but it is far lessened by only a few revisions.

Probably if I ever revamp that code the remaining instances would be replaced by templates.

This topic is closed to new replies.

Advertisement