Solved

Inheritance problem ?

Posted on 1998-06-08
14
557 Views
Last Modified: 2008-02-01
Hello, I have run into an error using code similar to this:

class Bar
{
// ...
public:
 Foo *pfoo;

 Bar(Foo *afoo,int i) :foo(afoo)
 {
  //...
 }
};

// I have a couple other classes like Bar, call them Bar1 and Bar2

class Foo
{
public:
  Bar a;
  Bar1 b;
  Bar2 c;
// ...
};

class Child:public Foo
{
// ...
public:
  Child(void):Foo(),a(this,1),b(this,2),c(this,3) {}
};

The idea is that Foo acts as abase class for a bunch of derived classes, which initialize their Bar members with different values. The Bar memebrs all have a pointer to the class that contains them, so that they can use its methods.
In the Child constructor, I get the following error:
"Foo:a" is not an unambiguous base class of "Child".
This happens with every single member of Foo I try to initialize, even with ints, longs, etc. (not just classes).
What does the error mean ? How do I fix it ? I realize that I can put all the initialization in the Foo constructor, but I don't want to do this since there will be too many parameters for me to pass.

0
Comment
Question by:Sinclair
  • 9
  • 4
14 Comments
 
LVL 2

Author Comment

by:Sinclair
ID: 1165356
Edited text of question
0
 
LVL 22

Expert Comment

by:nietod
ID: 1165357
answer coming.
0
 
LVL 22

Expert Comment

by:nietod
ID: 1165358
It is a little hard to tell if what I'm seeing is the real problem, or just a typo in your sample.  But the code

class Bar
   {
   // ...
   public:
    Foo *pfoo;

    Bar(Foo *afoo,int i) :foo(afoo)
    {
     //...
    }
   };

will complain that "foo is not a unambiguous base class or member of Bar.".  because it is not
"pfoo" (not "foo") however is a member.  If you change this to read

class Bar
   {
   // ...
   public:
    Foo *pfoo;

    Bar(Foo *afoo,int i) :pfoo(afoo)
    {
     //...
    }
   };

that should work.
0
 
LVL 22

Expert Comment

by:nietod
ID: 1165359
In the next case, the error is pretty clear.  Foo is a base of Child, so child can construct its Foo base, but it cannot construct the members of its Foo base,  The Foo has to construct its members.  The line that is in error is
     Child(void):Foo(),a(this,1),b(this,2),c(this,3) {}

what you need to do is provide a constructor for Foo that constructs a, b, and c.  Then the child should call this constructor to cosntruct its Foo,  sort of like.


class Foo
   {
   public:
     Bar a;
     Bar1 b;
     Bar2 c;
   Foo(int A, int B, int C) : a(this,A), b(this,B), c(this,C) {};
   // ...
   };

   class Child:public Foo
   {
   // ...
   public:
     Child(void):Foo(1,2,3) {}
   };
0
 
LVL 2

Author Comment

by:Sinclair
ID: 1165360
Thanks, nietod, and sorry for my typo in the Bar constructor. However, your solution (place all initialization in the Foo constructor) is something I have been trying to avoid, since there will be many, many parameters that I will need to pass - and they will differ depending on the child class, which means I will have to provide a Foo constructor for every possible combination of overridden Bar constructors. Is there another way to do this ?
0
 
LVL 22

Expert Comment

by:nietod
ID: 1165361
Don't blame me I didn't write the language!

Let me see if I understand your complaint.  Are you saying (just to be specific) there are say four ways to construct a Bar.  And a Foo needs to construct 3 bars so a Foo will need 3*4=12 constructors to handle every case?  Is that the problem you are faced with?

If so, there are ways around it...sort of.  

Let me know if that is the problem, or if not try to explain it more clearly.  An explanation of the real code wouldn't hurt.   Then I'll try to give you the best solution or a choice of a few good ones.
0
 

Expert Comment

by:lbrucher
ID: 1165362
Nietod was right in its explanation of the error. At the time
you try to initialize a, b and c from Child, they have already
been init'd because they belong to Foo and Foo had been init'd
already.

One quick way to still init a, b and c from Child is to have them as pointers to Bar, Bar1 and Bar2. So, you'd not need to
init them in the constructor. Just init them to NULL in Foo's constructor and new them anywhere you want in Child.
If you don't like pointers and your Bar class support the = operator you can also init them to some default value in Foo contructor and reassign them in Child: a = Bar(this, 1); b = Bar1(); etc...

Hope this helps.
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 22

Expert Comment

by:nietod
ID: 1165363
lbrucher, as you said, I was right.  so why did you answer?
0
 
LVL 2

Author Comment

by:Sinclair
ID: 1165364
nietod, sorry, I did not mean to pick on you :-)
Yes, I am having the exact problem you described (except with larger numbers). It looks like lbrucher has a workable solution (pointers initialized using new), so I am going to give points to him unless you can present a better solution (I am sort of afraid of messing up my code with memory leaks).
0
 
LVL 22

Accepted Solution

by:
nietod earned 100 total points
ID: 1165365
I think you understood, but just in case, that was a joke.  At times like this I often wish I did write the language.

That solution will work, but may be less efficient than others, and certainly can make your code harder to write.

One technique would be to use a parameter class heirarchy.  For example, say a Bar can be initialized in three ways, with a char, with an int, or with a double.  Then you would create a class hierarchy of 3 classes (and probably a 4th abstract base class) that will specify arguments to the Bar constructor.  Well, let me give you and example,

class BarConPrm :
{
};

class BarChrConPrm : public BarConPrm
{
public:
    char Chr;
};

class BarIntConPrm : public BarConPrm
{
public:
    int Int;
};

class BarDblConPrm : public BarConPrm
{
public:
    double Dbl;
};

continues.
0
 
LVL 22

Expert Comment

by:nietod
ID: 1165366
Then rather than having three constructors for Bar, you would have only one.  It would take a pointer or reference (constant reference is best in my opinion) to a parameter base class object.  the constructor would then typecast the parameter base class object to one of the concrete parameter class types, extract the parameters, and construct the Bar, like

Bar::Bar(const BarConPrm &Prm)
{
   const BarConPrm *PrmPtr = &Prm;
   const BarIntConPrm *Intptr = dynamic_cast<BarIntConPrm *,PrmPtr>;
   const BarChrConPrm *ChrPtr = dynamic_cast<BarChrConPrm *,PrmPtr>;
   const BarDblConPrm *DblPtr = dynamic_cast<BarDblConPrm *,PrmPtr>;

   if (IntPtr)
    ???? =  IntPtr->Int;
   else if (ChrPtr)
     ???? = ChrPtr->Chr;
   else
     ???? = DblPtr->Dbl;  
 
}
0
 
LVL 22

Expert Comment

by:nietod
ID: 1165367
Now say the class Foo has three Bar's that need to be constructed.  Foo's constructor will take 3 classes of the constructor parameter heirarchy, like

Foo::Foo(const BarPrmCon &P1,const BarPrmCon &P2,const BarPrmCon &P3) : Bar1(P1),Bar2(P2),Bar3(P3) {};

Now you have 1 bar constructor and 1 Foo constructor instead of 3 foo constructors and 9 bar constructors.  The constructors will be slighly slower, however.  But the total efficency (compared to embedded pointers) should be better.

Questions?  There are other options, but this is probably the best, at least as far as I can tell with what you've given me.
0
 
LVL 2

Author Comment

by:Sinclair
ID: 1165368
Thanks, nietod, I will do it that way and see if it works. I like your method because it provides even more flexibility than pointers and straight constructor overloading. I would give points to lbrucher, too, but I don't know if I can do that under the EE system...
0
 
LVL 22

Expert Comment

by:nietod
ID: 1165369
You can't if you are really generious, you can ask a "dummy" question just for him (put his name on it so no one else answers).  That's ussually nice to do, but I'm not so sure I would feel to compelled to do so in this case.  It was really inappropriate for him to have answered.  I had answered your oringinal question completely and you had asked for additional information.  He It is customary to let the expert who answered provide the information, or at least if another expert provides it to be helpful, they do so in a comment.  But I think he is knew and will learn...

If you have additional questions as you impliment this technique let me know.  I use it myself.
0

Featured Post

Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

Join & Write a Comment

Unlike C#, C++ doesn't have native support for sealing classes (so they cannot be sub-classed). At the cost of a virtual base class pointer it is possible to implement a pseudo sealing mechanism The trick is to virtually inherit from a base class…
Often, when implementing a feature, you won't know how certain events should be handled at the point where they occur and you'd rather defer to the user of your function or class. For example, a XML parser will extract a tag from the source code, wh…
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…
The viewer will be introduced to the member functions push_back and pop_back of the vector class. The video will teach the difference between the two as well as how to use each one along with its functionality.

747 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

16 Experts available now in Live!

Get 1:1 Help Now