Solved

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

Posted on 2008-10-14
11
302 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
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
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

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

Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This article will show you some of the more useful Standard Template Library (STL) algorithms through the use of working examples.  You will learn about how these algorithms fit into the STL architecture, how they work with STL containers, and why t…
Basic understanding on "OO- Object Orientation" is needed for designing a logical solution to solve a problem. Basic OOAD is a prerequisite for a coder to ensure that they follow the basic design of OO. This would help developers to understand the b…
The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.
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.

749 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