scarably
scarably

Reputation: 333

Derived class error: undefined type

Code looks like this:

class B {/*something*/};

class D1: public B {
public:
void set() = 0;
friend int D2::get(D1&);
private: 
int a;
}
class D2: public B {
public:
int get(D1& d) {return d.a;}
}

I've included "B.h" in both derived class' .h files("D1.h" and "D2.h") and also "D2.h" in D1, "D1.h" in D2...but keep getting compiling error:

...\D2.h ... use of undefined type D1

So what I'm doing wrong? Thanks.

Upvotes: 0

Views: 286

Answers (3)

AnT stands with Russia
AnT stands with Russia

Reputation: 320531

You created a circular inclusion: you included D1.h into D2.h and you also included D2.h into D1.h. Circular inclusion never works and never achieves anything.

Your circular inclusion is a direct consequence of circular dependency between your class definitions. In your code both class definitions refer to each other in a way that requires both class types to be complete (to be completely defined). This means that your code, as is, cannot be compiled, regardless of what you do. You need to break the circular dependency between class definitions.

In your case it can be done in the following way.

Keep D1.h unchanged, i.e. keep including D2.h into D1.h and keep the definition of class D1 as is.

However, do not include D1.h into D2.h Instead introduce a forward declaration of D1 into D2.h

class D1;

Change the definition of D2 to

class D2: public B {
public:
  int get(D1& d);
};

Note: do not attempt to define method get right in the definition of class D2. You have to relocate the definition of D2::get to some other place, where the full definition of D1 is also visible (like in D2.cpp for example, which should include both D1.h and D2.h)

int D2::get(D1& d) 
{
  return d.a;
}

That's it. A side-effect of defining D2::get this way is that it becomes non-inline. If you really want to keep it inline, you'll have to define it as

inline int D2::get(D1& d) 
{
  return d.a;
}

and also make sure it is somehow included only after the full definition of D1. You can place it, for example, into a third header file (D2_aux.h or something like that) and remember to include it after the D1.h.

Of course, a better way to try to solve this issue is to rethink the entire design. Do you really need that friend declaration inside D1? Maybe you should somehow redesign your code to eliminate the need for that friend declaration and thus eliminate this dependency.


Alternatively, you can resolve it by changing D1.h and keeping D2.h unchanged. However, to follow that path you'll have to replace your "fine-grained" friend declaration

friend int D2::get(D1&);

with a more sweeping and permissive

friend class D2;

and remove the inclusion of D2.h from D1.h.

The former friend declaration requires class D2 to be complete, which is actually what creates an "unbreakable" dependency. The latter declaration does not require D2 to be complete.

Upvotes: 3

Pete Becker
Pete Becker

Reputation: 76315

At the point were the code mentions D2 there hasn't been anything to say what D2 is (the compiler doesn't look ahead to figure it out). So you need to tell the compiler what D2 is by adding class D2; before the start of the definition of D1.

Upvotes: 0

user1202136
user1202136

Reputation: 11567

If D1's definition depends on D2 and D2's definition depends on D1, then you need to forward reference both classes:

class B;
class D1;
class D2;

Upvotes: 0

Related Questions