[C++] Polymorphism + Lists [Resolved]

Started by Apidcloud, November 30, 2012, 01:03:26 pm

Previous topic - Next topic

Apidcloud

November 30, 2012, 01:03:26 pm Last Edit: December 01, 2012, 02:50:04 pm by Apidcloud
Hello  :haha:
Yesterday I was coding a little bit, but I faced a little problem when trying to apply some polymorphism's concept.
Say that you have an Abstract Class A and that you have 2 classes, B and C that inherit from class A.

If we want to create a method/function and its argument to accept either class B or C, we can use an argument of class A as shown below:
void test(A &arg){//...}


The problem is: What if I want to use an argument(list of A's) in order to accept either a list of B's or C's ?
Something like this:
void function(list<A*> arg)
{
//...
}

void main(int argc, char*argv[])
{   list<B*> list_bs;
    function(list_bs); // Doesn't work here
   //...
}


Ok, I can understand why it doesn't work, since I use a template(list) of A pointers and not a single A pointer. However, I think that theoretically it should work according to polymorphism's concept.

Of course it can be solved by doing this way:
list<B*> list_bs;
list<A*> list_aux;
aux.assign(list_bs.begin(),list_bs.end());
function(aux);// this one is replaced


I just want to know if I thought about it correctly or not, and if there is a way of "forcing" it to accept the list of B's or C's.

Thanks  :)

Answer by Blizzard(once again):
Spoiler: ShowHide

Quote from: by Blizzard
A list<B*> does not inherit list<A*>, of course that won't work. But a template doesn't care about that. As long as the template would compile under B as T and as C under T, it will work. You not declaring the function as:


template <class T> function(list<A*> lst)


but as:


template <class T> function(list<T*> lst)
Instead of wanting to be somebody else, rather become somebody else



"I will treasure the knowledge like a squirrel treasures acorns."


Gibbo Glast 2D Engine - The sky is no longer a limit

Blizzard

November 30, 2012, 03:08:58 pm #1 Last Edit: November 30, 2012, 03:11:23 pm by Blizzard
You just have to declare the function as template function.

template <class T>
function(list<T*> ls)
{
   ls[0]->do_stuff();
}


C# has some extended concept called generic where you not only specify a method/function to work similarly to templates, you can also restrict it by defining that the template class has to use a specific class as base class. I can't remember the exact syntax right now, but the idea is something like:

Quotefunction(T obj) where T must be subclass of A


Sadly, C++ does not support that kind of thing, at least no that I know.

e.g. Here's a cool thing I did in hltypes:

template <class T> void hswap(T& a, T& b)
{
T temp = a;
a = b;
b = temp;
}


I have several other useful template functions like clamp, sgn, etc.
Check out Daygames and our games:

King of Booze 2      King of Booze: Never Ever
Drinking Game for Android      Never have I ever for Android
Drinking Game for iOS      Never have I ever for iOS


Quote from: winkioI do not speak to bricks, either as individuals or in wall form.

Quote from: Barney StinsonWhen I get sad, I stop being sad and be awesome instead. True story.

Apidcloud

November 30, 2012, 04:42:05 pm #2 Last Edit: November 30, 2012, 05:00:16 pm by Apidcloud
Thanks for your reply,

I think I understand why we use templates here, but how am I supposed to call that function? Also, as you mentioned, using templates won't "restrict" the function to the A inherited classes right?
For instance, say that I have this template(could be the clamp you posted):

template <class T>
   T Add(T a, T b) //C++ function template sample
   {
     return a+b;
   }

As we "don't" specify T's type, it can be "everything" correct? Okay, it can't be everything because it's done in compile time and unless + operator may be used, it won't run, but you don't "restrict" it to work only for numbers, right? (int, long, float, double, etc)

Anyway, I tried your code sample, but it's raising an error when either using function<list_of_As> or function<list_of_Bs_or_Cs>
What am I doing wrong here?

About C# way, I am aware of generic keyword, even though I didn't use it yet, so I will search for it :D

About your clamp example, clamp algorithm only limits the area from values, correct? e.g, is X is higher than Max, then X = Max.
Why are you using it on hltypes?(isn't that some kind of array? I can't find anything on google about hltypes to be sure)

Curiosity: could you also explain what's that sng algorithm?
Instead of wanting to be somebody else, rather become somebody else



"I will treasure the knowledge like a squirrel treasures acorns."


Gibbo Glast 2D Engine - The sky is no longer a limit

Blizzard

November 30, 2012, 06:06:54 pm #3 Last Edit: November 30, 2012, 06:08:52 pm by Blizzard
hltypes (High Level Types) is a library built on STL that adds additional methods to commonly used containers and structures as well as additional platform specific implementations (e.g. file system, directories and file access, etc.) and utility features (e.g. conversion between UTF8 (std::string, hstring) and Unicode (wchar_t) strings, special hmod functions that calculate modulo properly, hmin, hmax, etc.). We at Cateia wrote it.

Make sure that you declare AND define template functions completely in headers. As you already mentioned, actual variations of templates will be generated on compile time. Technically template is a hack in C++ that just generates the same function for needed implementations. Also make sure that you declared it correctly. T* and T are not the same thing.

You call the function just like any other function.

template <class T>
function(list<T*> ls)
{
    // whatever
}
// ...
list<A*> a;
function(a);
list<B*> b;
function(b);
list<C*> c;
function(c);


If you still can't get it working, post your actual code and I'll tell you what to do.
Check out Daygames and our games:

King of Booze 2      King of Booze: Never Ever
Drinking Game for Android      Never have I ever for Android
Drinking Game for iOS      Never have I ever for iOS


Quote from: winkioI do not speak to bricks, either as individuals or in wall form.

Quote from: Barney StinsonWhen I get sad, I stop being sad and be awesome instead. True story.

Apidcloud

..........I'm so damn stupid xD I was testing the function, so I created it below main and forgot to declare it above main( as we need to do in C)  :facepalm:
So sorry Blizzard. :^_^':

Although it works, it still doesn't restrict the classes that are enabled to go in, right? I mean, I just wanted the function to work to the classes that inherit from class A. I know that I could do it by overloading the same function(which is basically what template does) but that wouldn't be as "nice" as using polymorphism's concept. I wonder why it doesn't work with lists. Ok, I know but at the same time I don't understand it completely as I've shown in first post.
If we can use an argument A(a pointer) to accept its inherited classes, why doesn't it work when using lists of pointers? Am I saying something wrong? I think that it should work  :???:

I had no idea that hltypes was a library of common/useful methods , nor that your company wrote it, is it open source?
(Just checked Cateia website, you got some awesome games there oO I thought that your company was focused on 2D/platforms games ^^)



Instead of wanting to be somebody else, rather become somebody else



"I will treasure the knowledge like a squirrel treasures acorns."


Gibbo Glast 2D Engine - The sky is no longer a limit

Blizzard

Exactly, you can't have the restriction of which classes are allowed in a template function. I was experimenting with this recently, but I couldn't find a good way to do it.

It should work with lists normally. What kind of error are you getting?

Yeah, hltypes (among a few other libraries) is open source.
Check out Daygames and our games:

King of Booze 2      King of Booze: Never Ever
Drinking Game for Android      Never have I ever for Android
Drinking Game for iOS      Never have I ever for iOS


Quote from: winkioI do not speak to bricks, either as individuals or in wall form.

Quote from: Barney StinsonWhen I get sad, I stop being sad and be awesome instead. True story.

Apidcloud

Are you saying that List of A pointers as argument would accept lists of inherited classes? That's exactly what I'm saying that doesn't work - it raises an error of not exiting a user-defined conversion from class B*(which inherits from A) to class A*

Isn't that strange?

I'm going 2 search for the libraries,
Thanks
Instead of wanting to be somebody else, rather become somebody else



"I will treasure the knowledge like a squirrel treasures acorns."


Gibbo Glast 2D Engine - The sky is no longer a limit

Blizzard

December 01, 2012, 04:50:20 am #7 Last Edit: December 01, 2012, 04:53:04 am by Blizzard
A list<B*> does not inherit list<A*>, of course that won't work. But a template doesn't care about that. As long as the template would compile under B as T and as C under T, it will work. You not declaring the function as:

template <class T> function(list<A*> lst)


but as:

template <class T> function(list<T*> lst)


In hltypes we have better vectors, lists and deques so you can easily used a hlist and then call hlist::cast<A*>() or something like that.

hlist<B*> b;
hlist<A*> a1 = b.cast<A*>();
hlist<A*> a2 = b.dyn_cast<A*>(); // uses dynamic_cast


Though, your problem doesn't require hltypes to be solved.




We're using the same libraries for ARC: http://forum.chaos-project.com/index.php/topic,8901.0.html
Check out Daygames and our games:

King of Booze 2      King of Booze: Never Ever
Drinking Game for Android      Never have I ever for Android
Drinking Game for iOS      Never have I ever for iOS


Quote from: winkioI do not speak to bricks, either as individuals or in wall form.

Quote from: Barney StinsonWhen I get sad, I stop being sad and be awesome instead. True story.

Apidcloud

Quote from: Blizzard on December 01, 2012, 04:50:20 am
A list<B*> does not inherit list<A*>, of course that won't work.

I can understand that, but list's data type does inherit from A, since B < A. I mean, I think that "theoretically" it should work, just a shot though.

Quote from: Blizzard on December 01, 2012, 04:50:20 am
But a template doesn't care about that. As long as the template would compile under B as T and as C under T, it will work. You not declaring the function as:
template <class T> function(list<A*> lst)

but as:
template <class T> function(list<T*> lst)



Templates work, but it won't restrict which list's can access the function. Maybe I should just use the necessary overload functions? (I know that templates replace many overloads, but I can't figure out the best possible solution in this case)

Quote from: Blizzard on December 01, 2012, 04:50:20 am
In hltypes we have better vectors, lists and deques so you can easily used a hlist and then call hlist::cast<A*>() or something like that.

hlist<B*> b;
hlist<A*> a1 = b.cast<A*>();
hlist<A*> a2 = b.dyn_cast<A*>(); // uses dynamic_cast


Though, your problem doesn't require hltypes to be solved.

It's true that those casts would be pretty handy, but I do a "similar" thing when assigning a list of A* to a list of B* (not the same I know). One question, what would be the difference between first cast and the dynamic cast? Dynamic Cast works on runtime and its normally used with classes, in order to check if the parameter is either B or C.

Quote from: Blizzard on December 01, 2012, 04:50:20 am
We're using the same libraries for ARC: http://forum.chaos-project.com/index.php/topic,8901.0.html

I've read that thread yesterday, I read some examples with foreach macro and stuff :)


So, basically what's your advice in my particular case?
Should I just use overload functions or a template?

Thanks
Instead of wanting to be somebody else, rather become somebody else



"I will treasure the knowledge like a squirrel treasures acorns."


Gibbo Glast 2D Engine - The sky is no longer a limit

Blizzard

Use use templates, that's enough.

The difference between dynamic_cast and static_cast is basically that dynamic_cast will return NULL if the pointer can't be cast. Basically you can do stuff like "is this pointer of type X".

Let's say we have the classes A, B, C and D where B and C inherit A (as before) and D is separate.

A* a = new A();
B* b = new B();
C* c = new C();
D* d = new D();


Code: static_cast
A* a1 = static_cast<A*>(b); // works, obviously
A* a2 = static_cast<A*>(c); // works
static_cast<B*>(a1); // works
static_cast<C*>(a2); // works
(C*)a1; // same as previous static_cast actually, it's kinda the "C-way" to do it
static_cast<B*>(a); // does not crash, but the resulting pointer is actually wrong as "a" was not originally an instance of class B
static_cast<C*>(a); // does not crash, but the resulting pointer is actually wrong as "a" was not originally an instance of class C
static_cast<D*>(a); // does not crash, but the resulting pointer is actually wrong as "a" was not originally an instance of class D
static_cast<D*>(b); // does not crash, but the resulting pointer is actually wrong as "b" was not originally an instance of class D
static_cast<D*>(c); // does not crash, but the resulting pointer is actually wrong as "c" was not originally an instance of class D


Code: dynamic_cast
A* a1 = dynamic_cast<A*>(b); // works
A* a2 = dynamic_cast<A*>(c); // works
dynamic_cast<B*>(a1); // works
dynamic_cast<C*>(a2); // works
dynamic_cast<B*>(a); // result is NULL as "a" was not an instance of class B
dynamic_cast<C*>(a); // result is NULL as "a" was not an instance of class C
dynamic_cast<D*>(a); // result is NULL as "a" was not an instance of class D
dynamic_cast<D*>(b); // result is NULL as "b" was not an instance of class D
dynamic_cast<D*>(c); // result is NULL as "c" was not an instance of class D
if (dynamic_cast<D*>(a) != NULL) // "if a is of class D", this branch won't be executed
{
   // do stuff
}

Check out Daygames and our games:

King of Booze 2      King of Booze: Never Ever
Drinking Game for Android      Never have I ever for Android
Drinking Game for iOS      Never have I ever for iOS


Quote from: winkioI do not speak to bricks, either as individuals or in wall form.

Quote from: Barney StinsonWhen I get sad, I stop being sad and be awesome instead. True story.

Apidcloud

Thanks, i get it now.

It seems that this problem is solved, thanks again blizzard
im going to edit first post with template sample later on  :)

Instead of wanting to be somebody else, rather become somebody else



"I will treasure the knowledge like a squirrel treasures acorns."


Gibbo Glast 2D Engine - The sky is no longer a limit