标头中类的前向声明会导致类型不完整

时间:2016-02-28 21:58:02

标签: c++ header incomplete-type

我看了forward declaring以解决编译错误“错误:变量或字段'mov_avg'声明为void”。
以下场景:有一个data_proc.cpp具有main()包括自定义标头my_mov_avg.h,它嵌入了函数mov_avg(shared)。此外,头函数访问主文件中的class cl_shared。文件如下:

#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;
}

标题my_mov_avg.h文件:

//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; 
}

现在,当我向前声明以便定义函数参数类型时,我得到了这个编译错误:

 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;
       ^

如何让它编译,从头文件中访问类cl_shared是不好的设计?
我试图实现的是重复访问数据(这里分解为更改int)功能被称为。
我可以将class cl_shared分成单独的头文件并将其包含在两者中但我不确定,另外它会导致另一个头文件(可能没有必要)。
编辑在my_mov_avg.h中添加了参数  void mov_avg(cl_shared shared);但仍然会导致:

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

旁注:分解一个大的cpp文件的快速而肮脏的黑客是将函数放入单独的cpp并将#include "seperate.cpp"放在函数最初的位置。仅用于简单的程序。

2 个答案:

答案 0 :(得分:2)

前向声明仅在您将该类用作指针/引用且不尝试访问其任何成员时才有效。当您通过值传递时,编译器需要知道确切的大小.etc。该类型因此需要完整的类声明。

void mov_avg(cl_shared shared){

在这里,您传递的是值(即您正在传递堆栈上的共享副本),因此编译器需要完整的类声明。此外,当您访问类的成员时,切换到指针/引用传递是不够的,因为编译器需要知道类成员的内存布局。

你需要在某个地方声明cl_shared my_mov_arg.h可以在使用之前访问它。

在标题中声明非类成员函数(例如mov_arg)时,您应该将它们声明为内联。否则,函数定义将添加到您使用标头的每个源文件中,并导致编译错误。

EDIT。这应该做到这一点。如果需要,还可以将成员函数从cl_shared.h移动到cl_shared.cpp文件中。头文件顶部的 #pragma once 是为了确保每个编译单元只包含一次标题:

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);

答案 1 :(得分:0)

如果头文件只有

void mov_avg();

然后这将是一个不同的函数 - 一个不带参数的函数。 C ++强类型函数 - 重载可以有不同的参数签名但名称相同。所以它已经看到了move_avg()的声明,但没有声明move_avg(cl_shared shared)