Sign in to follow this  

Polymorphism question...

This topic is 4742 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Alright, I have a "mother" class called cUnit. It has children classes such as cWeapon, cSoldier, cStation etc. In order to store all these different units, I have a cUnit chain. Now here's a slight problem - each subclass has it's own variables and functions, so I can't put a general "virtual int GetXvariable()=0;" in cUnit, as many of these variables are not shared. Thus, I've been thinking that, instead of operating on a given cUnit with a cUnit pointer, I would instead create a pointer of the specified sub-class and then direct it at the given cUnit variable, based on it's type. Naturally, I cannot do "cWeapon * ptWeapon = &SomeUnit;" but instead I found out a, maybe a bit odd, way:
class Mother
{
 public:
 virtual void Speak()=0;     //just a standard abstract function 
 virtual void * GetSelf()=0; //this will return pointer to the Son class
};

class Son : public Mother
{ 
 public:
 void Speak() {cout<< "I can speak!"<<endl;};           //definition of this function
 void Personal() {cout << "I can get personal!"<<endl;};//a function available only in this sub-class
 
 void * GetSelf() {return this;} //returns pointer to self
};
This way, when I have the Mother class I can simply do this: Son * Sonny = (Son*)Mommy->GetSelf(); It seems to work fine but appears a bit awkward... Do you think this is a good appreach? Or should I rather try to create a more standard "DoSomething();" function for my cUnit class and simply call it every time I get to the unit? BTW, here's the full code of my first method:
#include <iostream>
#include <stdlib.h>

using namespace std;

class Mother
{
 public:
 virtual void Speak()=0;     //just a standard abstract function 
 virtual void * GetSelf()=0; //this will return pointer to the Son class
};

class Son : public Mother
{ 
 public:
 void Speak() {cout<< "I can speak!"<<endl;};           //definition of this function
 void Personal() {cout << "I can get personal!"<<endl;};//a function available only in this sub-class
 
 void * GetSelf() {return this;} //returns pointer to self
};

int main(int argc, char *argv[])
{
  Mother * Mom;             //create mom pointer
  Son * Sonny;              //create son pointer
  Son * SecondSon;          //create a pointer to son which will be obtained through mother
  
  Sonny = new Son;          //It's a boy!
  Mom = Sonny;              //now set the mom pointer to point at Sonny
    
  cout << "Son speaking:\n"; 
  Sonny->Speak();           //let the kid speak
  Sonny->Personal();        //let the kid get persona
  cout << "Mom Speaking:\n"; 
  Mom->Speak();             //let mommy speak about the son
  
  
  cout << "Son speaking through mother:\n";
  SecondSon = (Son*)Mom->GetSelf(); //assign the pointer to Sonny variable THROUGH mother variable
  SecondSon->Speak();               //speak
  SecondSon->Personal();            //get personal
  
  system("PAUSE");	
  return 0;
}



Share this post


Link to post
Share on other sites
SecondSon = (Son*)Mom->GetSelf();

produces the same results as just:

SecondSon = (Son*)Mom;

So ergh no real need for that function. Hope it falls into place (revelation time?) ;]
Btw don't forget to delete memory after use

...Heck no need to even use a pointer variable. If you have a pointer to a cUnit called unit & realise it's a cWeapon & want to call the fire method, just do:
((cWeapon*)unit)->fire();

Share this post


Link to post
Share on other sites
Quote:
Original post by ProPuke
SecondSon = (Son*)Mom->GetSelf();

produces the same results as just:

SecondSon = (Son*)Mom;

So ergh no real need for that function. Hope it falls into place (revelation time?) ;]
Btw don't forget to delete memory after use

...Heck no need to even use a pointer variable. If you have a pointer to a cUnit called unit & realise it's a cWeapon & want to call the fire method, just do:
((cWeapon*)unit)->fire();


... that was totally my second guess

;)

Share this post


Link to post
Share on other sites
This topic becomes more complex when you start having a lot of different derived classes. For example:


// Using structs so I don't have to write public everywhere - and only relevant data included
struct Base
{
virtual void Update() = 0;
};

struct Derived1 : Base
{
void Update() {DoDerived1Stuff();};

void DoDerived1Stuff();
};

struct Derived2 : Base
{
void Update() {DoDerived2Stuff();};

void DoDerived2Stuff();
};

// Somewhere else

std::vector<Base*> MyObjects;
// Push lots of different Derived1 and Derived2 objects onto MyObjects
// Note that at compile time you don't know what order the objects are in
// i.e. : is MyObjects[0] a Derived1 or Derived2?

// Method1:
MyObjects[0]->Update();

// Method2:
if(Derived1* thisObject = dynamic_cast<Derived1*>(MyObjects[0])
thisObject->DoDerived1Stuff;
if(Derived2* thisObject = dynamic_cast<Derived2*>(MyObjects[0])
thisObject->DoDerived2Stuff;




The problem with using a C-style cast is that it will cast your data to the requested type, no matter what, and to hell with the consequences - it's up to the programmer to ensure that's they're casting to the right type. A C++ dynamic_cast will only succeed if the object being cast to is actually that type of object, as follows:


Base* base = new Base;
Derived1* thisOb = dynamic_cast<Derived1*>(base); //fails

Base* base = new Derived1;
Derived1* thisOb = dynamic_cast<Derived1*>(base); //succeeds

Base* base = new Derived2;
Derived1* thisOb = dynamic_cast<Derived1*>(base); //fails




The code is now type-safe, which it isn't necessarily with a straight C-style cast.

The preferred option with many folks in C++ is to use a virtual function (ie Method 1), which you've already hinted at using. Dynamic_casts are seen as a second-string approach and are commonly seen as indicating a design flaw.

Oh, and btw - derived classes should be a type of their base-class - it models an 'is-a' relationship. Unless genetics has changed recently a son isn't likely to become a kind of mother [smile]. A better approach might be to have a Person abstract class, from which both Mother and Son are derived.

HTH,
Jim.

Edit : ignore my Mother/Son guff - I just re-read your post, and you're obviously using them as surrogates for a different inheritance-chain. Sorry!

Share this post


Link to post
Share on other sites

This topic is 4742 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

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