1

for single .cpp file- and .h file- we can move implementation from .cpp to .h file, but i can not do this for my case and occurred circularity :

my case is something like this (inclusion guard ignored):

//a.h

#include"stdio.h"
#include"b.h"

class A
{
public:
 void showfromA(const B& b);
 int index;
};

//a.cpp

#include"a.h"
void A::showfromA(const B& b)
{
printf("b.index=%i",b.index);
}

//b.h

 class B
{
public:
void showfromB();
int index;
};

//b.cpp

#include"a.h"
void B::showfromB()
{
A a;
a.index=1;
printf("a.index=%i",a.index);
}

//main.cpp

#include"b.h"
main()
{
B b;
b.showfromB();
}

circularity occurred because a.h include b.h but b.cpp include a.h. when .h files and .cpp files are separated ,the code is OK and we do not have circularity but when we try to merge .h file and .cpp file we encounter to circularity between class A and B and compile error. note that i want to move method implantation from .cpp file into * the class definition* in .h file

MD128
  • 501
  • 4
  • 12

4 Answers4

1

If you mean to move the definitions of member functions into the .h file and into the class, then it's impossible because of the circular dependency. You can, however, move the definitions to the .h file but keep them outside the class definition. In the latter case you'll have to make them inline to avoid linker errors.

Armen Tsirunyan
  • 130,161
  • 59
  • 324
  • 434
  • I mean, exactly,to move the definitions of member functions into the .h file and into the class, is there a " proof" that shows it is impossible?, isn't there any trick? – MD128 Jun 12 '15 at 01:26
  • The trick is to move the method's body outside of the class, to a location later in the header file where the other class is fully defined. If you tag the method as "inline", it will be logically equivalent to putting the method body inside the class declaration. – Jeremy Friesner Jun 12 '15 at 17:33
0

The circularity can be avoided by using guard statements in the header file.

#ifndef _A_H
    #define _A_H
    //Code of A.h
#endif

Similar changes can be done in B.h as well.

Pratap
  • 402
  • 2
  • 6
0

It's awkward, so I'd recommend using the .cpp files if you can, but if you absolutely need everything to be inline in the .h files, something like this will do the trick:

// main.cpp
#include "a.h"  // b.h will be included implicitly

int main(int, char**)
{
   A a;
   B b;
   a.showfromA(b);
   b.showfromB(a);
}

...

// a.h
#ifndef a_h
#define a_h

#include <stdio.h>
#include "b.h"

class B;

class A
{
public:
 void showfromA(const B & b) {printf("b's index is %i\n", b.index);}
 int index;
};

void B :: showfromB(const A & a) {printf("a's index is %i\n", a.index);}

#endif

...

// b.h -- don't #include this directly, include a.h instead
#ifndef b_h
#define b_h

#include <stdio.h>
#include "a.h"

class A;

class B
{
public:
 void showfromB(const A & a);    // implementation moved to a.h
 int index;
};

#endif
Jeremy Friesner
  • 70,199
  • 15
  • 131
  • 234
  • this approach was examined in my code, but failed because of redefinition error at line void B :: showfromB(const A & a) {printf("a's index is %i\n", a.index);} in header file, in face the question is how we can move implementation inside the class in header file. – MD128 Jun 11 '15 at 17:19
  • You can't, since at the time the B class is declared, the details of the A class are not known. You could mark the the showfromB method as inline, though. – Jeremy Friesner Jun 11 '15 at 21:54
0

You could forward-declare your struct in order to reduce header dependencies.

a.h

// we tell the compiler that B exists
struct B;

struct A {
    void showFromA(const B& b);
};

a.cpp

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

void A::showFromA(const B& b) {
    // B is complete here
}

b.h

// we tell the compiler that A exists
struct A;

struct B {
    void showFromB(const A& a);
};

b.cpp

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

void showFromB(const A& a) {
    // A is complete here
}

This syntax is okay since you receive references as arguments. A reference does not need to be complete, just like pointers. However, receiving arguments by value would not have worked, since value semantics require types to be complete.

Guillaume Racicot
  • 39,621
  • 9
  • 77
  • 141