• Advertisement
Sign in to follow this  

Polymorphism question...

This topic is 4818 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
Advertisement
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
Quote:
Original post by JimPrice

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



Hahahahahahaahhaahahhahaha :)

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement