Click here to Skip to main content
15,893,161 members
Please Sign up or sign in to vote.
4.00/5 (1 vote)
See more:
Hi,

Imagine I have some base class Animal.
And a derived class from it, say Cat.

Is it possible to do smth. like this:
Imagine I have a function which expects a pointer
to Animal object.

C++
void func(Animal * p)
{

}

Now, instead of a pointer to Animal object, I call
this function with a pointer to Cat class. e.g.

C++
Cat * cat = new Cat;
func(cat);


Now, inside the func function, I want to be able
to call Cat class methods on the passed cat pointer. Is it possible? And how?
Thanks.
Posted
Updated 5-Feb-13 20:15pm
v3

This is the key step in learning OOP before you approach the heart of it — virtual functions and late binding.

Here is the idea: derived class is assignment compatible with its base class:
C++
class Animal {/* ... */};
class Cat : public Animal {/* ... */};

Cat* cat = new Cat();
Animal* animal = cat; // but the opposite is not possible in general case


Isn't that apparent? Suppose you have some member of Cat missing from Animal.

If you assign a pointer to Cat to a pointer to Animal, you will get access to this non-existing member, which would "crash" the application, but the opposite case shown above is fine.

The answer to your question is inferred from this simple consideration. You compile-time class used in func in Animal. As Cat is animal, using it as a run-time class is fine: whatever this function does, it will operate with the members and instance of Cat always has.

—SA
 
Share this answer
 
v2
Comments
[no name] 6-Feb-13 2:56am    
On your last line, imagine Cat class has some methods: CatMeth1, CatMeth2, CatMeth3. Will I, using the "animal" pointer you declared on the last line, be able to access these methods? e.g., animal->CatMeth1; animal->CatMeth2, etc.
Sergey Alexandrovich Kryukov 6-Feb-13 9:58am    
Of course not, unless you down-cast it to Cat, to get a Cat pointer. As Animal can be something which is not Cat, the case can be successful or not. Type case defeats the purpose of OOP, abuses it. Here is where you are coming to the heart of OOP: virtual and pure abstract methods, method overrides, late binding. Keep going. So far, you are at the level of run-time vs compile-time types and assignment compatibility, not real OOP yet.
—SA
Emilio Garavaglia 6-Feb-13 11:01am    
Good in OOP school sense, "Type case defeats the purpose of OOP, abuses it" can become harmful if abused conversely: there is a risk to place in the base class all the potential methods of all it's potential derived. This is called a "god-object". The "good thing" stays somewhere in the middle. But no "school" models it.
Sergey Alexandrovich Kryukov 6-Feb-13 11:05am    
The "god object" is a well known anti-pattern. Good point. Modeling can be well learned, but teaching it can be a problem. OOP has its internal limitations...

But the way, I'm very sure that the ability to recognize and prevent anti-pattern is way more valuable then using design or architectural patterns.
—SA
[no name] 11-Feb-13 15:54pm    
Hi, guess what I can do is following. Declare virtual functions in the Animal class. Then, even if I pass a pointer to Cat object (e.g., catPointer) to a function that expects a pointer to Animal object and call say catPointer->CatMethod(), I guess the correct function from the Cat class will be called... right..?!
Ok, you have found out, that a Cat can be treated as an Animal object. That's called up-casting and that is done automatically by the compiler, as it is not dangerous.

The other direction requires some special knowledge. You have an Animal pointer and you "know" that the underlying object is a Cat object. You can in this instance perform a down-cast like this:

C++
Cat* pCat = dynamic_cast<Cat*> (pAnimal);


The dynamic cast operator will deliver a NULL pointer, in case pAnimal does not point to a Cat. Note that this requires RTTI (runtime type information) to be enabled in your compiler.

You also could do a plain old cast
C++
Cat* pCat = (Cat*) pAnimal;

which is however relatively dangerous, as you do not get a warning sign in case pAnimal does not point to a Cat. Not the recommended way to do it!
 
Share this answer
 
v2
Comments
[no name] 6-Feb-13 8:00am    
Hi, thanks for your response. Could you also please check the question I asked Sergey above?? thank you.
nv3 6-Feb-13 8:17am    
With a pointer to Animal you can only use methods of Animal (or any base classes of Animal). So if you want to use methods of Cat you have to have a pointer to Cat -- as simple as that. Casting the pointer from Animal* to Cat* is technically easy, as shown in my example. The difficult or dangerous part is that you must make sure that your pointer to Animal is really a pointer to a Cat object. If it isn't the cast will go wrong and undefined behaviour might result. When using RTTI and dynamic_cast you are on the safe side, because it returns a NULL pointer if your original pointer was not of type Cat. You should check that pointer for being non-NULL before continuing to use it, otherwise an access violation (segmentation fault on Linux) will result.
Yes its possible. One of the best sides of C++ is the downcasting and upcasting.
Downcasting is when from the Base class you change your object to one of the derived classes. The Upcasting is the opposite thing. Combined with virtual functions its really powerful thing. If you have base class Shape and some other child classes like Triangle, Circle and so on . When you type some function you don't need to check what type your object is, you can make the function about the Base class. And it will be working for all the child classes too. This is where the virtual functions kick in . Even when you upcast your item to the base class when you are about the execute of the virtual functions the right one will be executed(meaning the one defined in the child class of the object) and not the base one except if the object is from that class.
This helps you create functions with less checks which are easier to maintain.

One tip : Downcasting can be tricky and dangerous . When you do it use dynamic_cast. If the object cant be downcasted to the child class this function will return NULL. With simple check if the object is different from NULL you can save yourself many troubles :)
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900