Solved

c++; inheritence; multiple? or perhaps a better solution?

Posted on 2008-10-14
11
296 Views
Last Modified: 2010-04-21
I think maybe I'm going about my coding needs the wrong way, but I'm kind of in a rut and cannot seem to think outside the box at the moment.  Perhaps someone could either help me to fix my code or suggest a better alternative?  I'd really appreciate some aide.

I have a base class, ABase.  This class has a map<string,string>* parameter, and a few others, too.   This base class handles the setting/getting of the other parameters, and only generic access to the map (i.e. it gets a list of all keys, gets a list of all values, etc).  

Next, I define a derived class, ABaseCore, which targets specific key names to be used in the ABase->attrs.  It doesn't add any new parameters, it simply provides a convenient set of methods for setting/getting some parameters I consider core attributes.

Then, I define another derived class ABaseExtra, which does pretty much the same thing as ABaseCore, but different named methods for specific parameters.

There are about 3 or 4 other derived classes, which all have their own unique methods for handling specific parameters.  I'll skip the code on those, since they are pretty much the same thing as ABaseCore and ABaseExtra.

Now, the intent is to derive new classes from several of the previously derived classes (such as ABaseCore) - this is so my new classes have a nice collection of convenient-to-use method names which target the specific parameters.

Now, I understand the dynamics of referring to the base class in an unambiguous way.  part of the problem, however, is that I want the base class to have an overloaded operator<< which will output any of the higher level derived classes (such as ABC and DEF), but I can't quite figure out how to make it work.  I keep getting the error:

ambiguous conversions from 'ABC' to 'ABase &'

on the code:
ABC *a = new ABC();

cout << (*a)  << endl;

I have a feeling there is a better way to accomplish what I'm trying to do, but I've been staring at this code for about an hour and I think my brain will implode soon.  

I could simply forgo the 2nd-level of derivation, and simply put all the methods (from ABaseCore, etc) right into ABC, etc...  but that would be a lot of duplicate code... not every derived class will require the ABaseCore methods and not every derived class will require the ABaseExtra, but enough do that having a re-usable code segment makes sense.

Please, I beseech thee, aide!
//  base class

class ABase

{

 private:

  string p1;

  string p2;

  map<string,string> *attrs;
 

public:

  ABase()  { this->attrs = new map<string,string>; }

  ~ABase() { delete this->attrs; }
 

  void set(string key, string value) { (*this->attrs)[key] = value; }
 

  // code for p1 and p2 left out intentionally
 

  vector<string> *getKeys()       {  ...  }  //  truncated

  vector<string> *getValues()     {  ...  }  // for the sake

  string          get(string key) {  ...  }  // of brevity

  string          str() { ...  // convert the attrs into a string list }
 

  friend ostream &operator<<(ostream &strm, ABase &base) {

    strm << base.str();

    return strm;

  }

};
 

//  derived classes from the base

class ABaseCore : public ABase

{

public:

  void   setName(string newName) { this->set("name", newName); }

  string getName()               { return this->get("name");   }
 

  void   setType(string newType) { this->set("type", newType); }

  string getType()               { return this->get("type");   }

};
 
 

class ABaseExtra : public ABase

{

public:

  void   setFamily(string newFamily) { this->set("family", newFamily); }

  string getFamily()                 { return this->get("family");   }
 

  void   setGenus(string newGenus)   { this->set("genus", newGenus); }

  string getGenus()                  { return this->get("genus");   }

};
 
 

//  using collections of derived classes

class ABC : public ABaseCore, public ABaseExtra

{

  //  now this class has all the methods defined in all derived classes

};
 

class DEF : public ABaseCore, public ABaseSpecial, public ABaseID

{

  //  assume that ABaseSpecial and ABaseID are defined just like ABaseCore and ABaseExtra

};

Open in new window

0
Comment
Question by:BaconU
11 Comments
 
LVL 1

Expert Comment

by:link64
ID: 22717043
I havent played with c++ for a while, but have you tried doing:

ABase *abc = new ABC();
cout << (*a)  << endl;

Make the pointer of type ABase, but instantiate the ABaseCore ...
0
 
LVL 9

Assisted Solution

by:jhshukla
jhshukla earned 20 total points
ID: 22717178
0
 

Author Comment

by:BaconU
ID: 22717814
link64:  It won't work like that, simply due to the fact that ABase and ABC are not directly linked.  Now, I could say:

ABaseCore *abc = new ABC();

and that would work...  but then I lose the functionality of not only the other inherited classes (ABaseExtra, etc) but also the ABC-specific methods.   It is a good thought, though.

jhshukla:  That does answer the basic question of, how does one access the base members in an inherited class, especially one who has multiple levels of inheritence.  However, the problem of ambiguity still remains.  Supposing the ABase class contains a method "add(string text)"...   ABaseCore and ABaseExtra both inherit this method from ABase.  And now ABC inherits both ABaseCore and ABaseExtra, which has thus inherited two different sets of ABase.   As a result, ABC now contains two different inherited "add(string text)" methods.  

   Subsequent calls to the "add()" method on ABC have to know which sub-ABase is being referenced.

  I could say something like:

ABC *abc = new ABC();
abc->ABaseCore::add("blah");

  This does work.   But, supposing class GHI does not inherit ABaseCore, but ABaseExtra?   But now I have to remember to say:

ghi->ABaseExtra::add("blah");

  This is fine, except that it defeats the whole purpose of inheriting.  The point is to provide a common support structure, a foundation, which provides the most basic methods required to make the inheritors, and I (as the programmer) don't need to worry about which class inherits what, at least for the basic stuff.  

  I hope this makes sense.  

  I know that java doesn't allow multi-inheritance and probably for these very kind of issues. :)  

  I would like to add that I'm not even saying the way I'm doing this is correct.  If there is a more eloquent solution, I'd be happy to consider it..   and, and I bumped the points up to the max, in the hopes that a solution can be found.  In the meantime, I'll continue tinkering with the code. :)
0
 

Author Comment

by:BaconU
ID: 22717820
point bump
0
 
LVL 39

Accepted Solution

by:
itsmeandnobodyelse earned 230 total points
ID: 22719387
You need to derive virtually inorder to have only *one* ABase instance for the ABC objects. Then you have

                     ABase
                 /                    \
        ABaseCore      ABaseExtra
                 \                  /
                        ABC

and not

           ABase             ABase
               |                      |
        ABaseCore      ABaseExtra
                 \                  /
                        ABC

what leads to the ambiguouty.
0
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
LVL 39

Assisted Solution

by:itsmeandnobodyelse
itsmeandnobodyelse earned 230 total points
ID: 22719399
@#!!*#;

It seems that my code snippet was gone as I didn't check the code snippet checkbox.
//  using collections of derived classes

class ABC : virtual public ABaseCore, virtual public ABaseExtra

{

  //  now this class has all the methods defined in all derived classes

};

 

Open in new window

0
 
LVL 39

Assisted Solution

by:itsmeandnobodyelse
itsmeandnobodyelse earned 230 total points
ID: 22719425
Note, virtual derivation is not the key for any mapping problem.

You always should be aware that any public derivation is an "IS A" relation, e. g. for an  ABC object it should be correct to say "it is an ABase",  "it is an ABaseCore" and "it is an ABaseExtra". If one of these statements is not quite true, it would be better you define all functions virtually in ABase and derive only from one of ABaseCore or ABaseExtra (or from ABase directly) and reimplement the functions again.

0
 

Author Comment

by:BaconU
ID: 22722940
itsme:  I admit the "virtual" keyword gives me a little confusion in the cranial area.  

After first testing the example given by you, the ambiguity was not resolved when calling methods from ABC defined in ABase.  However, when I changed the ABaseCore definition to:

class ABaseCore  : virtual public ABase

.. and the same for the other classes derived directly from ABase, now it does not complain about ambiguity.

  So, it looks like the solution!  Yay!  I will of course do some reading up and research on the virtual keyword so that I may utilize it appropriately. :)

  Thanks!

0
 

Author Closing Comment

by:BaconU
ID: 31506081
As I noted in my comment to the thread, the 'virtual' keyword needed to be placed on the first derivation of ABase.  This seems to have solved the ambiguity.
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 22723119
>>>> class ABaseCore  : virtual public ABase
Yes, of course.

I used the virtual derivation only a few times within decades, so I always have some problems to find the right classes to which to place the virtual keyword to ;-)
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 22723211
Looking at my 'graphics' it should get clear:

The compiler needs to know that for the ABaseCore part and the ABaseExtra part used in ABC it should use only one part of ABase. Hence it needs the virtual keyword where the relation to ABase was defined.

In memory you would have

[ABase members][ABaseCore members][ABC members]
[ABaseExtra members]

ABC, ABaseCore, ABase (normally) share the same pointer, while the ABaseExtra has a different pointer.
0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

Introduction This article is a continuation of the C/C++ Visual Studio Express debugger series. Part 1 provided a quick start guide in using the debugger. Part 2 focused on additional topics in breakpoints. As your assignments become a little more …
Go is an acronym of golang, is a programming language developed Google in 2007. Go is a new language that is mostly in the C family, with significant input from Pascal/Modula/Oberon family. Hence Go arisen as low-level language with fast compilation…
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.

746 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now