Sign in to follow this  
aaron_ds

Forward declaration, undefined type

Recommended Posts

In keeping with my self appointed tradition of distilled examples, I present the following:
class B; //forward declaration to use type:B in A

class A {
  friend class B;
public:
  A(B * bptr = A::sbptr){
    A::sbptr=bptr;
  }

  void addProperty(const std::string & s, int i) {
    properties[s] = i;
    A::sbptr->addAByProperty(s, this); //line in question
  }

private:
  std::map < const std::string, int > properties;
  static B * sbptr;
};
B* A::sbptr=0;


class B {
public:
  void setAsCurrent() {
    A::sbptr = this;
  }

  std::list < A * > getAsByProperty(const std::string & s) {
    return a_map[s];
  }

private:
  void addAByProperty(const std::string & s, A * aptr) {
    a_map[s].push_back(aptr);
  }

  std::map < const std::string, std::list < A * > > a_map;
};


int main(int /* argc */, char * /* argv */ []) {
  B b1;
  b1.setAsCurrent();

  A a1;

  std::cin.get();
}
//mingw/gcc 3.4.2

I'm at a loss as to why I can't use sbptr->addAByProperty(s, this); inside of A. class B is declared with a forward declaration. It should work perfectly, IMHO. ;) I havn't delved into design patterns, but maybe there is one that can fit my case?

Share this post


Link to post
Share on other sites
It seems this question gets asked once a day..

Before you can invoke any of B's members, its definition must first be given. No exceptions.

Your forward declaration of B only tells the compiler that it exists somewhere - which is why you are able to define sbptr in class A, but are not able to call the method addAByProperty() using it.

This is why it is a good idea to always specify a class definition in its own header file, and its implementation in a source file.

Share this post


Link to post
Share on other sites
If A's member function definitions are moved to a source file, they can be given a complete declaration of both A and B, and then it will work.

Share this post


Link to post
Share on other sites
Quote:
Original post by Wavarian
It seems this question gets asked once a day..


Now, now...be nice to the poor programmer. Maybe he asks the question because he doesn't know the answer?

For situations such as this, this article tells you what you need to know. It's a bit of a long read, but worth it because that's what the programmers who know what they're doing do.

To distill it a bit:
You should nearly always place your class definitions in a header (.h or .hpp) file, with prototypes and member variables. Then place the actual function definition in a source (.c or .cpp) file. (The major exception to this rule being templates, but that doesn't apply in your situation.)

In any case, the advice already given is good. What you would do in this instance is create a header file "A.h" for class A:

class B; //forward declaration to use type:B in A

class A
{
friend class B;

public:
A(B * bptr);
void addProperty(const std::string & s, int i);

private:
std::map < const std::string, int > properties;
static B * sbptr;
};


and a source file for class A:

#include "B.h"
#include "A.h"

A::A(B * bptr = A::sbptr)
{
A::sbptr = bptr;
}

void A::addProperty(const std::string & s, int i)
{
properties[s] = i;
A::sbptr->addAByProperty(s, this); //line in question
}


as well as header and source for class B:

class A;

class B
{
public:
void setAsCurrent();

std::list < A * > getAsByProperty(const std::string & s);

private:
void addAByProperty(const std::string & s, A * aptr);

std::map < const std::string, std::list < A * > > a_map;
};



#include "B.h"
#include "A.h"

void B::setAsCurrent()
{
A::sbptr = this;
}

std::list < A * > B::getAsByProperty(const std::string & s)
{
return a_map[s];
}

void addAByProperty(const std::string & s, A * aptr)
{
a_map[s].push_back(aptr);
}



As you can see, this makes it so that header files only need the forward declaration, and source files can include the header files they need for full functionality.

Cheers,
Twilight Dragon

Share this post


Link to post
Share on other sites
Thank you very much. I've used forward declaractions before but this situation has never come up before.

ratings++ to everyone.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this