【问题标题】:Defining trouble. C++定义麻烦。 C++
【发布时间】:2011-07-05 12:52:24
【问题描述】:

这是简化的代码!我有 C++ 文件(在哪里实现)和头文件(在哪里是类定义)!

我有一个文件:Foo.cpp,其中包含 ma​​in.h。我有文件 Bar.cpp,它使用函数 Foo.cpp 并且还包括 ma​​in.h。它使用 struct 访问 Foo 对象并调用它的函数。但是 ma​​in.h 中定义的结构?我试图这样解决它:

**IN MAIN.H**
#pragma once

class Foo;
struct FoobarPackage {
    FoobarPackage(Foo *fooObj) {
        soso = fooObj;
    }
    Foo *soso;
};
* * *

**IN FOO.CPP**
#pragma once

#include "main.h"

class Foo {
    void doSomething(bool ololo) {
    if (ololo) //do something else
    }
};
* * *

**IN BAR.CPP**
#pragma once

#include "main.h"
#include "Foo.cpp"

class Bar {
    bool killAllHumans(FoobarPackage planet) {
        planet.soso->doSomething(true);
        return true;
    }
};
* * *

但它会导致:

Bar.cpp:8: error: invalid use of incomplete type "struct(WTF??!!! —  author's comment) Foo"
main.h:3: error: forward declaration of "struct(why struct?) Foo"

我的代码有什么问题?它也不是真正的代码。我简化了我的真实项目并削减了所有不需要的东西。 Foo.cpp 和 Bar.cpp 当然有它们的头文件,其中 Foo 和 Bar 类定义在 .cpp 文件中,它只是它们的实现。还从 main() 所在的 main.cpp 调用 killAllHumans()。

*已编辑* 我知道#include 与标题一起使用,但我写道它是“伪代码”。我在我的 readl 项目中使用头文件和 cpp 文件,并且只包含头文件,#pragma once 在我的头文件中。在这个问题中,我只简化我的代码!回答前请阅读所有问题!

*EDITED2* 现在尝试编译它。有用。奇怪。

谢谢。

【问题讨论】:

  • 为什么 cpp 文件中有 #pragma once?
  • 不要#include.cpp文件。
  • 我不这样做。我把所有不需要的东西都剪掉了,让我的代码像伪代码一样。抱歉,但我想你会明白这一点,因为我写了我有头文件并在最后包含它们,但没有人阅读所有问题。
  • 你好,@HiTECHNOLOGYs。您的伪代码令人困惑。如果您将实际代码减少到一个类似大小的包并包含一个实际的最小可编译示例程序,那会好得多。有关这将如何提供帮助的更多信息,请参阅sscce.org。顺便说一句,I 根据您的描述编写的代码在 g++ 中编译得很好。你用什么编译器?
  • 你好,@Rob。我知道我的代码现在很糟糕。我使用 g++。你用的女巫旗?

标签: c++ compiler-errors redefinition


【解决方案1】:

您不应在 C++ 中包含 .cpp(“代码文件”)。

始终在 Header (.h) 文件中进行定义。您必须创建 foo.h 和 bar.h 文件,然后将它们包含到 main.h

使用 .cpp 定义功能,使用 .h 定义函数原型,如下所示:

// foo.h
#pragma once

#include "main.h"

class Foo {
public:
    void doSomething(bool ololo);
};

// foo.cpp
#include "foo.h"

void Foo::doSomething(bool ololo)
{
    if (ololo) //do something else
}

我希望我已经足够清楚了。

【讨论】:

    【解决方案2】:

    问题

    你不应该#pragma once在源文件中,你不应该#include源文件相互进入。

    你的情况的问题(可能,但你的测试用例不准确):你#include "Foo.cpp",但在那一刻,编译器早在编译Foo.cpp时就已经触发了#pragma once。

    简单来说:编译器很混乱,因为你把源文件和头文件混在一起了。

    规范的作案手法

    • 每个类的标头/源代码对

      • 标头通常只有声明,例如class Foo { void someMethod(); };

      • 源包含标题并定义类成员,例如void Foo::someMethod() {...}

    • 其他翻译单元(“源文件”)然后可以愉快地#include标题

    示例

    foo.h

    #ifndef FOO_H
    #define FOO_H
    #pragma once   // note: compiler extension, do as
                   //       you prefer, advantage of #pragma 
                   //       once is near to nothing on today's
                   //       compilers, though
    
    class Foo {
    public:
        void someMethod();
    };
    
    #endif
    

    foo.cpp

    #include "foo.h"
    
    void Foo::someMethod() {
        // do something
    }
    

    然后,您可以像这样在其他翻译单元中使用它:

    ma​​in.cpp

    #include "foo.h"
    
    int main () {
        Foo foo;
        foo.doSomething();
    }
    

    【讨论】:

    • 在使用 C++ 时我更喜欢 #pragma once,#ifndef 对我来说更像 C 风格。只是一个意见:)
    • 与 C 无关。#pragma once 是一个编译器扩展(即使它被广泛支持)。 C++ 标准只制裁旧式#ifndef。
    • 反对者:不要躲在电脑屏幕后面,花时间解释。
    【解决方案3】:

    为我工作:

    $ cat main.h 
    #pragma once
    
    class Foo;
    struct FoobarPackage {
        FoobarPackage(Foo *fooObj) {
            soso = fooObj;
        }
        Foo *soso;
    };
    $ cat Foo.cpp 
    #pragma once
    
    #include "main.h"
    
    class Foo {
    public:
        void doSomething(bool ololo) {
        if (ololo) ; //do something else
       }
    };
    $ cat bar.cpp
    #pragma once
    
    #include "main.h"
    #include "Foo.cpp"
    
    class Bar {
        bool killAllHumans(FoobarPackage planet) {
            planet.soso->doSomething(true);
            return true;
        }
    };
    $ g++ -c bar.cpp
    bar.cpp:1:9: warning: #pragma once in main file
    $ $ g++ -v
    Using built-in specs.
    Target: i486-linux-gnu
    Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.4.3-4ubuntu5' --with-bugurl=file:///usr/share/doc/gcc-4.4/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --enable-shared --enable-multiarch --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.4 --program-suffix=-4.4 --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-plugin --enable-objc-gc --enable-targets=all --disable-werror --with-arch-32=i486 --with-tune=generic --enable-checking=release --build=i486-linux-gnu --host=i486-linux-gnu --target=i486-linux-gnu
    Thread model: posix
    gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5) 
    $
    

    编辑:正如每个人所指出的,这个程序仍然有很多错误。其中最重要的是它#includes 是一个 CPP 文件,没有明显的原因。

    【讨论】:

    • -1:恕我直言,这确实需要一个免责声明,例如“快速修复将是......但你不应该将翻译单元包含在彼此之间”
    • @phresnel - 没有“快速修复”。我回答的重点是 OPs 代码没有提出他抱怨的问题。尽管如此,我还是根据您的建议添加了一段。
    猜你喜欢
    • 2021-04-04
    • 1970-01-01
    • 2011-05-24
    • 1970-01-01
    • 2011-01-16
    • 1970-01-01
    • 2011-07-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多