Click here to Skip to main content
12,890,181 members (47,831 online)
Rate this:
Please Sign up or sign in to vote.
See more: C++

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.

void func(Animal * p)

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

Cat * cat = new 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?
Posted 5-Feb-13 19:54pm
Updated 5-Feb-13 20:15pm
Rate this: bad
Please Sign up or sign in to vote.

Solution 1

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:
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.

Matra Divat 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.
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.
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.
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.
Matra Divat 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..?!
Sergey Alexandrovich Kryukov 11-Feb-13 16:17pm
Let's separate concerns. 1) What you pass as an actual parameter for an explicit parameter has nothing to do with virtual. 2) what method is called is defined by the implicit parameter called "this", which is polymorphous in the following sense: you derive the class, the "this" parameter of the same function (no matter virtual or not) becomes a new type. 3) You are right, what you say will work; 4)Passing explicit parameters of the type of the class related to the hierarchy (say, base class) is very unusual and usually not needed.

Let's say:
class A {/*...*/}
A a = new A(/*...*/);
Some method has two (not) one parameters: a and b. A is also a parameter, "this", it tells the implementation how to address the instance.
class B : A {/*...*/}
B b = = new B(/*...*/);
b.SomeMethod(c); // same method! here, "this" == b; and the run-time type of "this" is B, but compile-time type is A.

Do you see the idea? You need to use "this" instead of passing the explicit parameter of the type A or B.

I don't think you are ready to discuss virtual methods yes. You need to understand one more step: virtual table and indirect call, or dispatched call, according to virtual table. But before that, you need to understand well inheritance and run-time types vs compile-time types and "this".

As I answered your original question, please accept it formally (green button), before you get to the heart of OOP, as it might last forever... :-)

Rate this: bad
Please Sign up or sign in to vote.

Solution 2

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:

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
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!
Matra Divat 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.
Rate this: bad
Please Sign up or sign in to vote.

Solution 3

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 :)

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

    Print Answers RSS
Top Experts
Last 24hrsThis month

Advertise | Privacy | Mobile
Web02 | 2.8.170424.1 | Last Updated 6 Feb 2013
Copyright © CodeProject, 1999-2017
All Rights Reserved. Terms of Service
Layout: fixed | fluid

CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100