Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Pointers exploiting polymorphism

Status
Not open for further replies.

polocar

Programmer
Sep 20, 2004
89
IT
Hi all,
I'm writing a Visual C++ 6.0 program, and I have a problem with polymorphism.

Suppose that you have defined the classes:

class BasicClass{
public:
int num_Basic;
};

class Deriv1Class : public BasicClass{
public:
int num_Deriv1;
};

class Deriv2Class : public BasicClass{
public:
int num_Deriv2;
};

and suppose you have defined a pointer

BasicClass *p;

For the polymorphic rules this pointer can point to BasiClass, Deriv1Class or Deriv2Class objects.
Now, suppose that at a certain point of the code you know that p is pointing to a Deriv1Class object,and you want to read its (public) num_Deriv1 member.
If you try to access directly to the member (with a statement as p->num_Deriv1), an error occurs, because num_Deriv1 is not a member of BasicClass (the class of p definition).
Indeed, if you define a temporary object of Deriv1Class and you write:

Deriv1Class tempDeriv1Obj;
tempDeriv1Obj = *p;
int n = tempDeriv1Obj.num_Deriv1;

another error occurs, because it isn't possible to convert a type from BasicClass to Deriv1Class.

At this point my question is:
if you have a pointer like that, is there a way to read this blessed num_Deriv1 member of the Deriv1Class object pointed?

Thank you very much
 
You need to use dynamic_cast:

BasicClass* p;

// set p to some derived class

Deriv1Class* p2 = dynamic_cast<Deriv1Class*>(p);
int n = p2->num_Deriv1;

Don't ever try to dereference a pointer to do this. If it even works, it would require unnecessary use of an = operator and the memory for the Deriv1Class. Just cast the pointer to another pointer as shown here.

You should also know that if p was not actually pointing to a Deriv1Class, the dynamic_cast should return NULL.
 
I'd suggest checking the conversion first, even if you know it is an instance of the derived class:
Code:
Deriv1Class* p2 = dynamic_cast<Deriv1Class*>(p);
if (p2 == 0)
    return; // error!
int n = p2->num_Deriv1;
Also, you might want to rethink your design if you find yourself doing this a lot (or even a little). The point of polymorphism is that you can treat your BasicClass pointer the same no matter what Derived class it is actually pointing to.
 
Hi timmay3141 and uolj,
I tried your suggestion but unfortunately it doesn't function:
I created a header file "project.h" and a source file "project.cpp", and I wrote this code:

project.h
---------

class BasicClass{
public:
int num_Basic;
};

class Deriv1Class : public BasicClass{
public:
int num_Deriv1;
};

class Deriv2Class : public BasicClass{
public:
int num_Deriv2;
};


project.cpp
-----------

#include "project.h"

int main(){

Deriv1Class d1c_obj; // Deriv1Class object

d1c_obj.num_Basic = 4; // initialization of
d1c_obj.num_Deriv1 = 6; // d1c_obj object

BasicClass *p1 = &d1c_obj; // pointer to BasicClass that points to a Deriv1Class object

Deriv1Class *p2 = dynamic_cast<Deriv1Class*>(p1);

int i = p2->num_Deriv1;

return 0;
}


when I compile, 1 error occurs:
error C2683: dynamic_cast : 'BasicClass' is not a polymorphic type

Is there anything wrong in my code?

Thanks guys!
 
In order for this to work, BasicClass must have at least 1 virtual function (otherwise there really isn't a need to be using polymorphism anyway). If there is some reason that you need to accomplish this without any virtual functions, you should be able to use reinterpret_cast to do it.
 
Hi timmay3141,
thank you for your answer.
Actually, I have no need to insert a virtual function in the base class (the only reason to do that is just to apply the dynamic_cast), so I decided to re-think the data structure of the project and transform the base and derived classes in classes not related each other.

There is a thing that I don't understand: today I have read in a C++ theory book that the dynamic_cast has been designed expressly for the polymorphism, in particular if the user has to call a method present only in the derived class.
If I understood correctly, when I have a pointer to a base class and I call a method, 4 cases can happen:
1) the method is defined in the base class and it's not virtual: in this case, it is executed.
2) the method is defined in the base class and it's virtual; cases 2a) and 2b) are possible:
2a) the method is defined in the derived class dynamically pointed by the pointer: it is executed.
2b) the method isn't defined in the derived class: the virtual method of the base class is executed.
3) the method is defined in the derived class but not in the base class: the compiler produces an error.

The dynamic_cast would have the task to avoid the case n.3: I define a pointer to the derived class and assign (thanks to dyn. c.) the old pointer to it, so I can use the derived class method.
But then the question is:
why, to be able to use the dynamic cast, at least 1 virtual method must be defined in the base class, if the dynamic_cast has just the purpose to manage the cases in which the user wants to call a method present only in the derived class (and not in the base class as virtual?)
In other words, I want to use the dyn. c. just in the cases where the base class has no virtual functions!

Thanks
 
>3) the method is defined in the derived class but not in the base class: the compiler produces an error.

Really? A derived class is everthing is everything its base class is.

>why, to be able to use the dynamic cast, at least 1 virtual method must be defined in the base class,

Make the destructor virtual as it should be anyway.



/Per

&quot;It was a work of art, flawless, sublime. A triumph equaled only by its monumental failure.&quot;
 
> Really? A derived class is everthing is everything its base class is.

Yes, I re-tried and had the confirm.
When you define a pointer to a base class, even if you dinamically assign the pointer to an object of a derived class, you can use the methods of the base class and only the methods of the derived class (the pointer dinamically links to) that are also defined in the base class as virtual.

> Make the destructor virtual as it should be anyway.

Ok, thank you
 
>When you define a pointer to a base class, even if you dinamically assign the pointer to an object of a derived class, you can use the methods of the base class and only the methods of the derived class

Not sure I understand you , but if you've only instantiated a "base" then you of course can't access "derived" stuff.

Code:
class Base
{
public:
	Base() {}
	virtual ~Base() {}

	virtual void Foo() { cout << "Base::Foo" << endl; }
};

class Derived : public Base
{
public:
	Derived():Base() {}
	virtual ~Derived() {}

	virtual void Foo() { cout << "Derived::Foo" << endl; }

	void Bar(){ cout << "Derived::Bar" << endl; };
};

void func1(Base& b)
{
	b.Foo();
}

void func2(Derived& d)
{
	d.Foo();
	d.Bar();
}

...
{
	Base* b1 = new Derived();
	func1(*b1); // OK b1 is a Base
	func2(dynamic_cast<Derived&>(*b1));// OK b1 is a Derived

	Base* b2 = new Base();
	func1(*b2); // OK b2 is a Base
	func2(dynamic_cast<Derived&>(*b2)); // ERROR b2 is NOT a Derived

	delete b1;
	delete b2;
}

You can regars inheritance as a "is a" relationship. A Derived "is a" Base, but that doesn't mean a Base is a Derived (like "Guitar is a Instrument" != "All Instruments are guitars")

The whole point of polymorfism is that you don't need to know the derived class' interface. On some, excptional, places you do need to make a dynamic cast like the one mentioned, but "normally" (if there is such a thing) you don't need to.

You define a "known" interface (=the base class) that is passed around and provide different implementations (=derived classes) without the ones needing to know who is really doing the job. If you feel you often need to make dynamic casts polymorfism probably isn't the right thing for the tasks you try to solve.






/Per

&quot;It was a work of art, flawless, sublime. A triumph equaled only by its monumental failure.&quot;
 
While I agree with what you said above, technically a derived class can have functionality beyond that of the base class.

PerFnurt said:
>3) the method is defined in the derived class but not in the base class: the compiler produces an error.

Really? A derived class is everthing is everything its base class is.
I think polocar was just pointing that #3 is correct. If you have a base class pointer pointing to a derived class instance, you cannot call methods from the derived class that don't exist in the base class. Of course, you generally wouldn't want to do that anyway, which is why you should rethink your design if you find yourself using dynamic_cast.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top