Search code examples
c++headerincomplete-type

Forward declaration of class in header causes incomplete type


I had a look at forward declaring to get around the compile error " error: variable or field ‘mov_avg’ declared void".
Following scenario: There is one data_proc.cpp having the main() including a custom header my_mov_avg.h, which embeds the function mov_avg(shared). Furthermore the header function accesses class cl_shared inside the main-file. The files look like:

#include <string.h>     //c++ headers
#include <iostream> //red?

#include "my_mov_avg.h" //outsourced function

using namespace std;

/* class accessed from header*/
class cl_shared {
public:
    //constructor 
    cl_shared() { };

    int getint() {
        return a;
    }
private:
    int a;
};
cl_shared shared; //class object

/*main calling function inside header*/
int main(int argc, char **argv){
    mov_avg(shared);
    getchar();
    return 0;
}

The header my_mov_avg.h file:

//in .h
void say();
void mov_avg();

//in .cpp
#include <string.h>     
#include <iostream> 
#include "my_mov_avg.h"


void say() {
    std::cout << "Ohai from another .cpp file!";
}
class cl_shared; //Forward declaration
void mov_avg(cl_shared shared){
        std::cout<<" int from class: "<< shared.getint()<< std::endl; 
}

Now as I forward declared so that the function argument type is defined I got this compile error:

 error: ‘shared’ has incomplete type
 void mov_avg(cl_shared shared){
      ^
 /my_mov_avg.cpp:9:11: error: forward declaration of ‘class cl_shared’
 class cl_shared;
       ^

How to get it to compile and is it bad design to access the class cl_shared from the header?
What I try to achieve is to repeatedly access data (here broken down to a changing int) from where the header-function was called.
I could break out the class cl_shared into a separate header file and include it in both but I'm not sure, additionally it causes another header file(which might not be necessary).
EDIT added argument inside the my_mov_avg.h
void mov_avg(cl_shared shared); but still causes:

my_mov_avg.h:3:14: error: variable or field ‘mov_avg’ declared void
 void mov_avg(cl_shared shared);

sidenote: a quick and dirty hack to break down one big cpp-file is to place the function into a seperate cpp and place #include "seperate.cpp" where the function originally was. Use only with simple programs.


Solution

  • Forward declarations only work if you use the class as a pointer / reference and do not attempt to access any of its members. When you pass by value the compiler needs to know the exact size .etc. of the type and therefore needs the full class declaration.

    void mov_avg(cl_shared shared){
    

    Here you are passing by value (that is you are passing a copy of shared on the stack) therefore the compiler needs the full class declaration. Also as you access members of the class, switching to pass by pointer/reference will not be enough as the compiler will need to know the memory layout of class members.

    You need to declare cl_shared somewhere my_mov_arg.h can access it prior to using it.

    On a sidetone when you declare non-class member functions in a header i.e. like mov_arg, you should declare them as inline. Otherwise the function definition will be added to every source file you use the header in and cause compilation errors.

    EDIT. This should do it. You can also move the member functions from cl_shared.h into a cl_shared.cpp file if you want. The #pragma once at the top of the header files are to ensure the header only gets included once per compilation unit:

    cl_shared.h:

    #pragma once
    
    class cl_shared {
        public:
        //constructor 
        cl_shared() { };
    
        int getint() {
            return a;
        }
    private:
        int a;
    };
    

    my_mov_avg.h

    #pragma once
    #include "cl_shared.h"
    
    void say();
    void mov_avg(cl_shared shared);