Polymorphism question...

Started by
3 comments, last by Koobazaur 19 years, 4 months ago
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;
}



Comrade, Listen! The Glorious Commonwealth's first Airship has been compromised! Who is the saboteur? Who can be saved? Uncover what the passengers are hiding and write the grisly conclusion of its final hours in an open-ended, player-driven adventure. Dziekujemy! -- Karaski: What Goes Up...
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();
_______________________________ ________ _____ ___ __ _`By offloading cognitive load to the computer, programmers are able to design more elegant systems' - Unununium OS regarding Python
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

;)
Comrade, Listen! The Glorious Commonwealth's first Airship has been compromised! Who is the saboteur? Who can be saved? Uncover what the passengers are hiding and write the grisly conclusion of its final hours in an open-ended, player-driven adventure. Dziekujemy! -- Karaski: What Goes Up...
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 includedstruct Base{ virtual void Update() = 0;};struct Derived1 : Base{ void Update() {DoDerived1Stuff();};  void DoDerived1Stuff(); };struct Derived2 : Base{ void Update() {DoDerived2Stuff();}; void DoDerived2Stuff();}; // Somewhere elsestd::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); //failsBase* base = new Derived1;Derived1* thisOb = dynamic_cast<Derived1*>(base); //succeedsBase* 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!
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 :)

Comrade, Listen! The Glorious Commonwealth's first Airship has been compromised! Who is the saboteur? Who can be saved? Uncover what the passengers are hiding and write the grisly conclusion of its final hours in an open-ended, player-driven adventure. Dziekujemy! -- Karaski: What Goes Up...

This topic is closed to new replies.

Advertisement