1
#include<bits/stdc++.h>
using namespace std;

class B;
class A{
    public: 
        int a_i=10;
        void A_lookup(B b){
            cout << b.b_i <<endl;
        }
};
class B{
    public:
        int b_i=20;
        void B_lookup(A a){
            cout << a.a_i <<endl;
        }
};

int main(void){
    A a;
    B b;
    a.A_lookup(b);

In this case, I have two classes both of which would visit each other members. When compiling such a .cpp file, there are two piece of information:

sample2.cpp:8:25: error: 'b' has incomplete type void A_lookup(B b){

sample2.cpp:4:7: note: forward declaration of 'class B' class B;

Why could class A still not visit the member b_i of class B after class B has been declared ahead of class A. How should I fix such a error?

Virux
  • 138
  • 9
  • You haven't defined the class `B` before declaring an element of type `B` (in `void A_lookup(B b)`). This confused the compiler... – DeBARtha Mar 07 '22 at 03:29

1 Answers1

3

The problem is that when you wrote:

void A_lookup(B b){ //this statement needs B to be a complete type
            cout << b.b_i <<endl; //this also needs B to be a complete type
        }

In the above member function definition, the parameter b is of type B. And for B b to work, B must be a complete type. Since you have only declared class B and not defined it, you get the mentioned error. Moreover, the expression b.b_i needs B to be a complete type as well.

Solution

You can solve this by declaring the member function A_lookup inside the class A and then defining it later when B is a complete type as shown below:

#include <iostream>
class B;
class A{
    public: 
        int a_i=10;

        //only a declaration here
        void A_lookup(B b);        
};
class B{
    public:
        int b_i=20;
        void B_lookup(A a){
            std::cout << a.a_i <<std::endl;
        }
};
//this is a definition. At this point B is a complete type 
void A::A_lookup(B b)
{
    std::cout << b.b_i <<std::endl;
}
int main(void){
    A a;
    B b;
    a.A_lookup(b);
}

Demo

Solution 2

Note that you can also make the parameters a and b to be a reference to const A or reference to const B respectively as shown below. Doing so has some advantages like now the parameter a and b need not be complete type. But still expression a.a_i and b.b_i will need A and B respectively to be complete type. Also, now the argument will not be copied since now they will be passed by reference instead of by value.

#include <iostream>
class B;
class A{
    public: 
        int a_i=10;
        void A_lookup(const B& b); //HERE ALSO void A_lookup(const B& b){  std::cout << b.b_i <<std::endl;} WILL NOT WORK
                   
};
class B{
    public:
        int b_i=20;
        void B_lookup(const A& a){
            std::cout << a.a_i <<std::endl;
        }
};

void A::A_lookup(const B& b)
{
    std::cout << b.b_i <<std::endl;
}
int main(void){
    A a;
    B b;
    a.A_lookup(b);
}

Demo


Also refer to Why should I not #include <bits/stdc++.h>?.

Jason
  • 36,170
  • 5
  • 26
  • 60
  • 1
    Even better, `A_lookup()` should take a `const B&` parameter, and `B_lookup()` should take a `const A&` parameter. – Remy Lebeau Mar 07 '22 at 04:20
  • @RemyLebeau Yes that will remove the restriction that the parameter `b` or `a` should be a complete type but still the expressions `b.b_i` and `a.a_i` will need `B` and `A` to be a complete type respectively. [Demo](https://onlinegdb.com/jDOWXTRqT). I have placed a comment in the above linked demo. If i was not clear making my point(through the demo and my comment), please let me know. I was thinking of making the parameters as "reference to const" before posting my answer, but then i decided not to. – Jason Mar 07 '22 at 04:30
  • There are other benefits. Pass by reference doesn't require copying, and pass by const reference allows the use of temporaries at the call site. You should really never pass an object by value. – user207421 Mar 07 '22 at 04:40
  • @user207421 Yes i am aware of that. But since it is not directly related to the question i did not bother mentioning that. In any case, i have added `const B&b` and `const A&a` version in my edited answer as solution 2. – Jason Mar 07 '22 at 04:47