Forward declaration, undefined type

Started by
3 comments, last by aaron_ds 18 years, 9 months ago
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 = i;
    A::sbptr-&gt;addAByProperty(s, <span class="cpp-keyword">this</span>); <span class="cpp-comment">//line in question</span>
  }

<span class="cpp-keyword">private</span>:
  std::map &lt; <span class="cpp-keyword">const</span> std::string, <span class="cpp-keyword">int</span> &gt; properties;
  <span class="cpp-keyword">static</span> B * sbptr;
};
B* A::sbptr=<span class="cpp-number">0</span>;


<span class="cpp-keyword">class</span> B {
<span class="cpp-keyword">public</span>:
  <span class="cpp-keyword">void</span> setAsCurrent() {
    A::sbptr = <span class="cpp-keyword">this</span>;
  }

  std::list &lt; A * &gt; getAsByProperty(<span class="cpp-keyword">const</span> std::string &amp; s) {
    <span class="cpp-keyword">return</span> a_map;
  }

<span class="cpp-keyword">private</span>:
  <span class="cpp-keyword">void</span> addAByProperty(<span class="cpp-keyword">const</span> std::string &amp; s, A * aptr) {
    a_map.push_back(aptr);
  }

  std::map &lt; <span class="cpp-keyword">const</span> std::string, std::list &lt; A * &gt; &gt; a_map;
};


<span class="cpp-keyword">int</span> main(<span class="cpp-keyword">int</span> <span class="cpp-comment">/* argc */</span>, <span class="cpp-keyword">char</span> * <span class="cpp-comment">/* argv */</span> []) {
  B b1;
  b1.setAsCurrent();

  A a1;

  std::cin.get();
}
<span class="cpp-comment">//mingw/gcc 3.4.2</span>

</pre></div><!–ENDSCRIPT–>

I'm at a loss as to why I can't use sbptr-&gt;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 &#111;ne that can fit my case?
Advertisement
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.
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.
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 Aclass 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 = i;<br>    A::sbptr-&gt;addAByProperty(s, <span class="cpp-keyword">this</span>); <span class="cpp-comment">//line in question</span><br>}<br><br></pre></div><!–ENDSCRIPT–><br>as well as header and source for class B:<br><!–STARTSCRIPT–><!–source lang="cpp"–><div class="source"><pre><br><span class="cpp-keyword">class</span> A;<br><br><span class="cpp-keyword">class</span> B<br>{<br><span class="cpp-keyword">public</span>:<br>    <span class="cpp-keyword">void</span> setAsCurrent();<br><br>    std::list &lt; A * &gt; getAsByProperty(<span class="cpp-keyword">const</span> std::string &amp; s);<br><br><span class="cpp-keyword">private</span>:<br>    <span class="cpp-keyword">void</span> addAByProperty(<span class="cpp-keyword">const</span> std::string &amp; s, A * aptr);<br><br>    std::map &lt; <span class="cpp-keyword">const</span> std::string, std::list &lt; A * &gt; &gt; a_map;<br>};<br><br></pre></div><!–ENDSCRIPT–><br><!–STARTSCRIPT–><!–source lang="cpp"–><div class="source"><pre><br><span class="cpp-directive">#include</span> <span class="cpp-literal">"B.h"</span><br><span class="cpp-directive">#include</span> <span class="cpp-literal">"A.h"</span><br><br><span class="cpp-keyword">void</span> B::setAsCurrent()<br>{<br>    A::sbptr = <span class="cpp-keyword">this</span>;<br>}<br><br>std::list &lt; A * &gt; B::getAsByProperty(<span class="cpp-keyword">const</span> std::string &amp; s)<br>{<br>    <span class="cpp-keyword">return</span> a_map;<br>}<br><br><span class="cpp-keyword">void</span> addAByProperty(<span class="cpp-keyword">const</span> std::string &amp; s, A * aptr)<br>{<br>    a_map.push_back(aptr);<br>}<br><br></pre></div><!–ENDSCRIPT–><br><br>As you can see, this makes it so that header files &#111;nly need the forward declaration, and source files can include the header files they need for full functionality.<br><br>Cheers,<br>Twilight Dragon
{[JohnE, Chief Architect and Senior Programmer, Twilight Dragon Media{[+++{GCC/MinGW}+++{Code::Blocks IDE}+++{wxWidgets Cross-Platform Native UI Framework}+++
Thank you very much. I've used forward declaractions before but this situation has never come up before.

ratings++ to everyone.

This topic is closed to new replies.

Advertisement