Robert
Robert

Reputation: 13

Sharing info between classes

I am trying to share info between classes using information from here, except that I am not able to get these two classes to compile and thus to communicate with each other.

So, what I want is for ClassB to get a reference to ClassA, and ClassB to be initialized in ClassA.

Compiler errors (using g++):

In member function 'void ClassA::foo()':
hello.cpp:9: error: 'ClassB' was not declared in this scope
hello.cpp:9: error: 'someB' was not declared in this scope
hello.cpp:9: error: expected type-specifier before 'ClassB'
hello.cpp:9: error: expected ';' before 'ClassB'

So then I try adding class ClassB; before ClassA,

like:

class ClassB; // just this here.

class ClassA; // all of classA here.

class ClassB; // all of classB here.

And I get:

hello.cpp: In member function 'void ClassA::foo()':
hello.cpp:11: error: invalid use of incomplete type 'struct ClassB'
hello.cpp:3: error: forward declaration of 'struct ClassB'
hello.cpp:12: error: invalid use of incomplete type 'struct ClassB'
hello.cpp:3: error: forward declaration of 'struct ClassB'


This is the code that am I trying to use based on the website above:

include stdio.h

class ClassA {
    public:
        void foo() {
            ClassB *someB = new ClassB();
            someB->setRelative(this);
        }

        void bar() {
            printf("B is communicating with me =)\n");
        }
};

class ClassB {

    ClassA *m_relative;

    public:
        void setRelative(ClassA *other) {
            this->m_relative = other;
        }

        void foo() {
            m_relative->bar();
        }
};

Upvotes: 1

Views: 360

Answers (3)

Mario
Mario

Reputation: 36487

You're obviously having a circular dependency here, something you can't really solve using headers only (might be possible with some macro tricks, but I wouldn't worry about).

What you should do is splitting your code into declarations (headers) and implementations.

a.h

// only include this file once per translation unit
#pragma once

// tell the compiler B is going to be a class,
// so B* is a pointer to a class - nothing more is needed for now.
class B;

// full declaration of A
class A {
    B *child;

public:
    A(void);
}

a.cpp

#include "a.h" // included whenever the structure/size of A has to be known
#include "b.h" // same for B

A::A(void) : child(new B(this)) {
    // do something with child or...
    B * = new B(this);
}

b.h

// only include this file once per translation unit
#pragma once

// again, just tell the compiler A is going to be a class
class A;

class B {
    A *parent;
public:
    B(A *pparent);
}

b.cpp

#include "a.h"
#include "b.h"

B::B(A *pparent) : parent(pparent) {
    // do something with parent
}

Upvotes: 3

Olaf Dietsche
Olaf Dietsche

Reputation: 74028

class A needs a full definition of class B in order to create it and call someB->setRelative(this). class B needs a full definition of class A in order to call m_relative->bar(). So this is sort of a chicken and egg problem.

You can break this circle only by splitting class and method declaration in header files and method definitions in cpp files.

Upvotes: 0

Ahmed Kato
Ahmed Kato

Reputation: 1707

Like This question Each class (A and B) should have a header file and an implementation file.

Each header file (e.g. A.h) should not include the other header file (e.g. B.h) but may include a forward reference to the other class (e.g. a statement like class B;), and may then use pointers and/or references to the other class in its declaration (e.g. class A may contain a B* as a data member and/or as a method parameter).

Each CPP file (e.g. A.cpp) may include more than one header file (e.g. A.h and B.h). It's recommended that each CPP file should include its own header file first (e.g. A.cpp should include A.h and then B.h, whereas B.cpp should include B.h and then A.h).

Each header file should contain only the declaration, and not the definition of the class: for example it will list the signatures of the class' methods, but not the method bodies/implementations (the method bodies/implementations will be in the .cpp file, not in the header file). Because the header files don't contain implemention details, they therefore don't depend on (don't need to see) details of other classes; at most they need to know that, for example, B is the name of a class: which it can get from a forward declaratin, instead of by including a header file in another header file.

For example:

// a.h Class B; // forward declaration

lass A {
   void foo(B* b); // pointers and references to forward-declared classes are ok
};


// b.h
Class A; // forward declaration

Class B {
   void bar(A& a); // pointers and references to forward-declared classes are ok
};


// a.cpp
#include "a.h"
#include "b.h"

void A::foo(B* b) {
   b->bar(*this); // full declaration of B visible, ok to call members now
}


// b.cpp
#include "a.h"
#include "b.h"

void B::bar(A& a) {
   a.foo(this); // full declaration of A visible, ok to call members now
}

Upvotes: 1

Related Questions