casting

Y

Yin99

I have the following code (Mammal base class, Dog inherits from
Mammal):
Dog *spot= new Dog;
spot->Speak();
Mammal *fido = dynamic_cast<Mammal*>(spot);
fido->Speak();
Dog *bandit = dynamic_cast<Dog*>(fido);
bandit->Speak();

I would expect the output:
Woof!
Mammal speak!
Woof!

Instead, I get the output:
Woof!
Woof!
Woof!

Since Speak is a virtual method, shouldn't it know when it is casted to
a Mammal,
and call the Speak method in that class? Thanks,

Yin99

--- header files -----
class Mammal
{
public:
void Move() const;
virtual void Speak() const;
Mammal();
virtual ~Mammal();
private:
int itsAge;
};

class Dog : public Mammal
{
public:
void WagTail();
void Speak() const;
void Move() const;
Dog();
virtual ~Dog();
};
 
P

Phlip

Yin99 said:
I have the following code (Mammal base class, Dog inherits from
Mammal):
Dog *spot= new Dog;
spot->Speak();
Mammal *fido = dynamic_cast<Mammal*>(spot);

Try this:

Mammal * fido = spot;

No typecast; it was just confusing you.

Now you know the purpose of virtual methods. fido behaves like a dog, yet
you can pass it to functions that take any mammal. They may remain unaware
it is a dog, so you can upgrade them with the behaviors of other mammals,
without changing their source.
 
J

Jakob Bieling

Yin99 said:
I have the following code (Mammal base class, Dog inherits from
Mammal):
Dog *spot= new Dog;
spot->Speak();
Mammal *fido = dynamic_cast<Mammal*>(spot);
fido->Speak();
Dog *bandit = dynamic_cast<Dog*>(fido);
bandit->Speak();

I would expect the output:
Woof!
Mammal speak!
Woof!

Instead, I get the output:
Woof!
Woof!
Woof!

Since Speak is a virtual method, shouldn't it know when it is casted
to a Mammal,
and call the Speak method in that class? Thanks,

No, it is just the other way around. Because Speak is virtual, it
knows what the real object is and calls the approriate method.

If you do not want this behaviour, make Speak non virtual and you
will see the output you expected.

hth
 
H

Howard

Yin99 said:
I have the following code (Mammal base class, Dog inherits from
Mammal):
Dog *spot= new Dog;
spot->Speak();
Mammal *fido = dynamic_cast<Mammal*>(spot);
fido->Speak();
Dog *bandit = dynamic_cast<Dog*>(fido);
bandit->Speak();

I would expect the output:
Woof!
Mammal speak!
Woof!

Instead, I get the output:
Woof!
Woof!
Woof!

Since Speak is a virtual method, shouldn't it know when it is casted to
a Mammal,
and call the Speak method in that class? Thanks,

No. The cast is irrelevant.

Since the object that was created was a Dog, it calls the Dog member. The
ability to assign a derived class pointer (Dog*) to a base class pointer
(Mammal*) is exactly what allows us to store a variety of derived class
pointers in a container declared to hold pointers to base class objects, and
later get the correct polymorphic behavior for each one.

The casting is not needed to store a Dog* in a Mammal* pointer. Since a Dog
IS a Mammal, a pointer to a Dog object can always be stored, without
casting, in a Mammal*.

Now, the question is, is this just experimentation on your part, or do you
actually NEED to be able to call the Mammal function for an object you've
created initially as a Dog?

-Howard
 
T

Tomás

Since Speak is a virtual method, shouldn't it know when it is casted to
a Mammal,
and call the Speak method in that class?


That's exactly what a non-virtual method would do.

The whole point of virtual methods is that, regardless of the pointer's
type or the reference's type, that the very special method gets called.

Non-virtual methods, on the other hand, have no such faculty, and the
function that gets invoked depends entirely on the type of the pointer or
reference. Make the function non-virtual, then recompile it, and you'll
get the expected results.

A lot of compilers achieve this "virtual function" behaviour by embedding
a function pointer inside the actual object. For instance, a "Mammal"
could be implemented like as follows:

struct Mammal
{
void (*Speak)(); //Pointer to the function
};


Then later in your code, regardless of the type of the reference or the
pointer, it just uses this "embedded pointer" to figure out which
function to invoke.

(Actually, instead of storing a pointer for each individual virtual
function, it stores one pointer to a "v-table" which contains all the
pointers for a particular type). So for instance, a "Dog" could be
implemented as follows:

struct Dog
{
V_Table *v_table;

void PlayFetch();
};

and then the "Dog" v-table could be defined elsewhere as:

struct V_Table
{
void (*Speak)();
void (*Eat)();
};

And you could have the particular "Dog" v-table as follows:

V_Table Dog_V_Table = { Dog::Speak, Dog::Eat };




-Tomás
 
Y

Yin99

thanks for the replies. So in conclusion, if the method is virtual, it
will always know the type and
call the method from the type it was created. Take Virtual away, and
it will call the method
from what ever type you cast it to.

Is there any way to call the Mammal function for the object initially
created as a Dog with
using virtual method?

BTW: When I run Mammal * fido = spot; now the pointer is Mammal, but
it still cleverly
calls Speak from Dog. I know this is the point of polymorphism, but it
gets back to question above-
what if I really do want to call it on Mammal? Is the only way
fido->Mammal::Speak(); ?


Yin99
 
J

Jakob Bieling

Yin99 said:
Is there any way to call the Mammal function for the object initially
created as a Dog with using virtual method?

Using your original names for variables:

spot->Mammal::Speak ();
BTW: When I run Mammal * fido = spot; now the pointer is Mammal, but
it still cleverly calls Speak from Dog. I know this is the point of
polymorphism, but it gets back to question above- what if I really do
want to call it on Mammal? Is the only way fido->Mammal::Speak(); ?

Yes.

hth
 
H

Howard

Jakob Bieling said:
Using your original names for variables:

spot->Mammal::Speak ();


Yes.

Well, not the ONLY way. You could also "slice" the Dog (yum, what a
picture!) into a Mammal object, by casting (*spot) as a Mammal.

-Howard
 
J

Jakob Bieling

Well, not the ONLY way. You could also "slice" the Dog (yum, what a
picture!) into a Mammal object, by casting (*spot) as a Mammal.

Yes, you are right. But a little note to the OP: slicing creates a
*copy* of the 'Mammal' part of 'Dog'. So the original 'Dog' object will
not be modified.

regards
 

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

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,596
Members
45,135
Latest member
VeronaShap
Top