Sign in to follow this  
owl

Overloaded virtual method not being called

Recommended Posts

I've been debuging this for a while and I don't seem to notice what I'm doing wrong... I have a base class:
class cgui_object
{
    protected:
        cgui_object ( void );

    public:
        virtual void on_draw () {}
};


and a derived class:
class cgui_box : public cgui_object
{
    public:
        cgui_box ( void );

        virtual void on_draw (); // which is defined in the cpp, it just couts
};


Then I have a list of cgui_objects that gets iterated and the method on_draw is called from within cgui_object:
void cgui_object::draw()
{
	// Don't draw if not initialized
	if(!pgui || !visible) return;

	prenderer->set_orthographic_pixels(&viewport);

	prenderer->push_attribute_all();
	on_draw(); // This line gets executed every pass.
	prenderer->pop_attribute_all();

	children.move_first();
	while (!children.eof())
	{
		children.value().draw();
		children.move_next();
	}
}


cgui_object::on_draw() gets executed, but the overloaded on_draw() method in cgui_box is not. Any ideas? EDIT: Yes, cgui_box is of base cgui_object

Share this post


Link to post
Share on other sites
The problem seems to be that the container I'm storing the base objects is of type <base> instead of <base*>. If I copy the derived-base instead of using a pointer, the overloaded function doesn't get called. I don't really understand why thouhg...

Share this post


Link to post
Share on other sites
Sounds like it might be the same problem that was recently discussed here, specifically 'object slicing' (I could be wrong about that though).

Share this post


Link to post
Share on other sites
yep, seems to be that.

Why, oh why can't we just have:

int main()
{
derived d;
base b = d;

b.draw();
return 0;
}



Working with polimorphism?

Share this post


Link to post
Share on other sites
Dynamic dispatch only operates through pointers and references in C++, because a non-pointer non-reference can never be anything but its static type, and thus no dynamic dispatch is necessary or possible.

What you just posted slices the object. A derived is a base, but a base is not a derived.

Share this post


Link to post
Share on other sites
Quote:
Original post by jpetrie
Dynamic dispatch only operates through pointers and references in C++, because a non-pointer non-reference can never be anything but its static type, and thus no dynamic dispatch is necessary or possible.


I can see that now. To me polimorphism in c++ feels a little bit more hackish now than before. I can give virtual functions to a class but they won't be virtual at all when the instance is static. bleh.

Share this post


Link to post
Share on other sites
You have the same situation in languages like C# or Java. When you say

Base b = new Derived();

b is actually a pointer to a derived, you just don't have to write it out.
(Assuming Base and Derived are classes and not structs in C#.)

By the way, we're talking about "overriding", not "overloading".

[Edited by - DevFred on June 6, 2009 4:58:38 AM]

Share this post


Link to post
Share on other sites
Quote:
Original post by owl
I can see that now. To me polimorphism in c++ feels a little bit more hackish now than before. I can give virtual functions to a class but they won't be virtual at all when the instance is static. bleh.


Hackish? Why? The language did exactly what one would expect it to do. You had an object of type cgui_object, so the language correctly chose the cgui_object::on_draw() implementation when you called on_draw(). There's nothing hackish about that.

I think you still haven't quite understood what the actual problem is. Since your container holds actual cgui_object objects rather than pointers to cgui_object objects, what happened when you tried to put an instance of cgui_box into the container is that a cgui_object got copy-constructed from a cgui_box. Understand? A __cgui_object__ got constructed, NOT a cgui_box.

My apologies if I assumed wrong, and you had actually already understood that.

Share this post


Link to post
Share on other sites
The part I don't like is that if you create a static instance of the derived class and you do Base* b = &Derived, polimorphism works.

As jpetrie said, the language works like that and I've to get used to it.

Share this post


Link to post
Share on other sites
You have to think about what it means to have an instance of an object; it means that at some location there are sizeof(cgui_object) bytes that make up that instance, amongst other things.

If polymorphism was to work on instances and a cgui_object could actually be any of it's subclasses how would anyone know how much memory to allocate for it (at compile time)? How could you have an array of cgui_objects where each element takes up a different amount of space?

Technically a language could allow for it, but then you would have all sorts of things having to be calculated at runtime instead of being known at compile time, and lots of trickery when it comes to iteration, and probably many more complications that I'm not thinking of at the moment.

Share this post


Link to post
Share on other sites
Okay, maybe I'm just not getting it but why is everyone going on about whether polymorphism 'works' with actual instances (as opposed to pointers to instances)?? I mean it's not as if polymorphism somehow 'breaks' if you use instances and not pointers. Polymorphism does not come into play when invoking methods on an instance, simply because there is no NEED for it as the compiler knows the type of the instance and thus doesn't have to defer the decision about which method to call until runtime. So what? The correct method will still get called!

I got the impression that the original poster was operating on the notion that ...


Derived d;
Base b = d;




would result in b being a Derived, when in reality it doesn't do anything more than invoke operator = on instance b, with d being the right-hand side argument to the operator. In other words, the values of any members present in Base will be copied from d to b. But afterwards b will still be a Base, and hence a subsequent invocation of a virtual method on b will use the Base version of that method. This has nothing to do with polymorphism 'not working'.

Share this post


Link to post
Share on other sites
Quote:
Original post by Red Ant
Okay, maybe I'm just not getting it but why is everyone going on about whether polymorphism 'works' with actual instances (as opposed to pointers to instances)?? I mean it's not as if polymorphism somehow 'breaks' if you use instances and not pointers. Polymorphism does not come into play when invoking methods on an instance, simply because there is no NEED for it as the compiler knows the type of the instance and thus doesn't have to defer the decision about which method to call until runtime. So what? The correct method will still get called!

I got the impression that the original poster was operating on the notion that ...

*** Source Snippet Removed ***

would result in b being a Derived, when in reality it doesn't do anything more than invoke operator = on instance b, with d being the right-hand side argument to the operator. In other words, the values of any members present in Base will be copied from d to b. But afterwards b will still be a Base, and hence a subsequent invocation of a virtual method on b will use the Base version of that method. This has nothing to do with polymorphism 'not working'.


Yes that was exactly the misunderstanding I was having. I was expecting that in the asignment:

Derived d;
Base b = d;



b would behave exactly as the base of the derived class it was initialized with (in relation to it's virtual methods). But this can't happen as it would require an implicit second instance of the derived class to work with it, and that would be even uglier than object slicing.

I got it straight now.

Share this post


Link to post
Share on other sites
Quote:
Original post by Red Ant
in reality it doesn't do anything more than invoke operator =

Actually, it invokes the copy constructor ;)

Share this post


Link to post
Share on other sites
Good catch. :) I knew that, really. Was just too excited when I posted, so I momentarily forgot it. :P

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this