polymorphism in c++

Started by
8 comments, last by krez 22 years, 2 months ago
is there any way to use polymorphism between two derived classes based on the same base class? i.e.:

class CBase
  {
  public:
    int p_value;
  };
class CDerived1 : public CBase
  {
  public:
    virtual void SomeFunc(void);
  };
class CDerived2 : public CBase
  {
  public:
    virtual void SomeOtherFunc(void);
  };
class CBoth : public CDerived1, CDerived2
  {
  public:
    void SomeFunc(void);
    void SomeOtherFunc(void);
  };
 
now, if i try to use "p_value" from CBoth, i get an error telling me "member is ambiguous"... this was obvious, but i was hoping the compiler would realize that it is the same base class two steps back, so the "p_value"s would be the same thing. apparently not so, if there any way to do this? just in case there is a completely different approach to use, here is what i am REALLY trying to do: i have a base class CItem, from which is derived CWeapon and CArmor. now, some things are both armor and weapon (such as a spiked shield)... so i need both the "weapon"- and "armor"-specific members and functions, and all classes have the generic "item"-members. i can''t just derive a "CWeaponArmor" class from CItem because then it won''t be either a CWeapon or a CArmor, just a CItem... did that make sense? please help someone --- krez (krezisback@aol.com)
--- krez ([email="krez_AT_optonline_DOT_net"]krez_AT_optonline_DOT_net[/email])
Advertisement
ok, i just rushed trough you post, but i believe what you may
need is to make CBase a virtual base class.

CDerived1: virtual CBase
CDerived2: virtual CBase
CBoth : CDerived1, CDerived2

this is straight from the top off my head.
When declaring base classes, the ''virtual'' keyword means that only one copy of the class will be held by derived classes.

The compiler cannot guess. In some cases, Derived1 and Derived2 are supposed to keep separate state, in some other, they must merge their common parts.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
ah, thank you both very much!


--- krez (krezisback@aol.com)
--- krez ([email="krez_AT_optonline_DOT_net"]krez_AT_optonline_DOT_net[/email])
Diamond-shaped inheritance is the root of all evil. It''s sometimes appropriate, but be very careful that this is what you want.
Just in case you dont want to use a virtual base class (ie: you want Derived1 and Derived2 to each have their own copies of CBase and all of its members), you can first typecast your CBoth back to either Derived1 or Derived2, and then cast from that back to CBase.

As an example, given the code
    CBoth* both = new CBoth();CBase* base1 = (CBase*)(CDerived1*)both;base1->p_value = 1;CBase* base2 = (CBase*)(CDerived2*)both;base2->p_value = 2;printf("%d, %d", base1->p_value, base2->p_value);    


without a virtual base class it prints "1, 2"
with a virtual base class it prints "2, 2"


Edited by - LordKronos on February 1, 2002 1:43:10 PM
Ron FrazierKronos Softwarewww.kronos-software.comMiko & Molly - Taking Puzzle Games to A Whole New Dimension
quote:Original post by Stoffel
Diamond-shaped inheritance is the root of all evil. It's sometimes appropriate, but be very careful that this is what you want.


Wrong. Not fully understanding your tools is the root of all evil (or at least most of the evil). That and bad design.

Edited by - LordKronos on February 1, 2002 1:43:59 PM
Ron FrazierKronos Softwarewww.kronos-software.comMiko & Molly - Taking Puzzle Games to A Whole New Dimension
quote:Original post by Stoffel
Diamond-shaped inheritance is the root of all evil. It''s sometimes appropriate, but be very careful that this is what you want.

yah, i had a feeling that this was a sketchy way of doing things as far as non-confusion is concerned... but that seems the simplest way of doing what i want to do... i need two classes derived from the same base class, and a third class that inherits the base class, and a few functions/members from each of the other two derived classes... this seems less messy than trying to handle all the possiblities within one class...
LordKronos: i want CBoth to have only one copy of the base class stuff, like so:
class CBase  {  public:    void BFunc(void);  };class CDerived1 : public virtual CBase  {  public:    virtual void D1Func(void);  };class CDerived2 : public virtual CBase  {  public:    virtual void D2Func(void);  };class CBoth : public CDerived1, public CDerived2  {  public:    void D1Func(void);    void D2Func(void);  }; 

so, a CBoth object will be a combination of the 2 derived classes, but the stuff from the CBase class is shared...
are there any down sides to doing this, other than the possibility of confusing myself?

--- krez (krezisback@aol.com)
--- krez ([email="krez_AT_optonline_DOT_net"]krez_AT_optonline_DOT_net[/email])
No, there arent really any downsides to this, its just a matter of knowing when to use virtual and when not to. In general, virtual is usually more appropriate, but it depends on the case. If CDerived1 and CDerived2 each need to maintain their own state independant of each other, then you dont want to use virtual. Lets give a few examples.

Lets say you want to make some file handling classes (this will be kinda like the fstream classes). You could define a CFile base class which holds the file handle and takes care of opening and closing the file. Then you could derive a CInputFile class which defines methods for reading from the filehandle, and a COutputFile class which defines methods for writing to the filehandle. Both of these classes would inherit the virtual base class CFile. Then you could create the CInOutFile class which inherits both CInputFile and COutputFile, so you can read to and write from a file. In this case, you want to always read and write the same file, so in CInOutFile, you want it to have a single file handle for input and output, rather than 1 file handle for input, 1 file handle for output.

Now, instead, lets say you want to make winsock classes. So, you make a CSocket base class that contains code for establishing/managing a socket (UDP or TCP), including keeping track socket handles (and other fun stuff). Now you create 2 derived classes, CTCPSocket which establishes a TCP connection, and a CUDPSocket which establishes a UDP connection. Both of these classes derive NON-virtually from CSocket. Then you make a CConnection class which inherits from both CTCPSocket and CUDPSocket. When constructed, this class initiates both a TCP and a UDP connection to the same server. Just for explanation, this is good for games because sometimes you want to guarantee that data gets there but dont care how fast it is (a good candidate for TCP), and other times you want to send data as fast as possible but dont care if it gets there because maybe you will be sending updated info in a few seconds (a good candiate for UDP). Anyway, since CConnection establishes separate sockets for TCP and UDP, you need to make sure that the inherited CTCPSocket and CUDPSocket each have their own socket handles (and other fun stuff), and the only way to do this it to make sure each has its own copy of CSocket (which holds the socket handle). Thus, in this case, using a virtual base class would be a disaster...so we want a NON virtaul base class.

Hopefully this gives you a little better idea of when to use each type of inheritance.
Ron FrazierKronos Softwarewww.kronos-software.comMiko & Molly - Taking Puzzle Games to A Whole New Dimension
excellent!
thank you...

--- krez (krezisback@aol.com)
--- krez ([email="krez_AT_optonline_DOT_net"]krez_AT_optonline_DOT_net[/email])

This topic is closed to new replies.

Advertisement