繁体   English   中英

在实现(.cpp)文件中不包括相应的头文件(.h)仍可以编译吗?

[英]Not including the corresponding header (.h) file in the implementation (.cpp) file still compiles?

我今天写了一个简单的示例,只是为了看看它是否可以编译,当我发现它可以编译时,我实际上感到非常惊讶!

这是示例:

hello.h

#ifndef HELLO_H
#define HELLO_H

// Function prototype
void say_hello();

#endif

HELLO.CPP

注意:这不包括“ hello.h”,就像我在永远的历史中见过的每个C ++示例一样!

// #include "hello.h" <-- Commented out. The corresponding header is NOT included.

#include <iostream>

void say_hello() {
    std::cout << "Hello!" << std::endl;
}

main.cpp中

#include "hello.h"

int main() {
    say_hello();
}

然后,我将“ hello.cpp”编译为静态库,如下所示:

g++ -c hello.cpp
ar -rvs libhello.a hello.o

然后,我编译了“主”应用程序并将其链接到库

g++ -o main main.cpp -L. -lhello

并运行它,它执行得很好!

./main

你好!


当我感到惊讶的时候...我确实理解为什么这样做。 这是因为“ hello.cpp”中的函数未声明为静态,因此具有外部链接并且可以从外部看到。 将其设置为静态将由于未定义引用而导致链接失败。

因此,这就是问题……如果这行得通,那么为什么每个地方的人总是在“ .cpp”实现文件中包括“ .h”头文件和函数声明。 显然,如果仅定义自由函数,则没有必要,并且如果不包含头文件,一切都可以正常工作。

那么为什么我们总是将其包括在内? -是否只是对链接器的工作原理普遍缺乏了解? 还是还有更多?

让我们更改您的hello.cpp

// #include "hello.h" <-- Commented out. The corresponding header is NOT included.

#include <iostream>

int say_hello() {
    std::cout << "Hello!" << std::endl;
    return 0;
}

这将与以前的版本一样编译。 它也可能会链接-但不正确。 返回类型错误。

这是未定义的行为,但是在许多常见的实现中,您将不使用它,因为您不使用返回值,并且通常在寄存器中返回它。 但是,不必一定如此-您在运行时可能会遇到非常奇怪的错误。 特别是如果差异稍微复杂一些(例如,当调用方期望int时返回double -通常会在其他寄存器中返回)。

另一方面,如果您写了:

#include "hello.h"

#include <iostream>

int say_hello() {
    std::cout << "Hello!" << std::endl;
    return 0;
}

然后,头文件中的声明将与CPP文件中的定义不匹配-并且您将获得一个不错的,易于理解的编译器错误消息。

实际上,这是一个好主意,如果您没有外部函数的声明,GCC会抱怨。 (如果您在命令行上使用-wall -werror,它将停止您的构建。)

如果您有一个类,则需要包含它以获取该类及其成员的声明,以使其定义匹配。 否则,您将无法分开定义和声明。

/// C.h
class C
{
public:
    C();
private:
    int _i;
};
/// C.cpp
// #include "C.h"

C::C() : _i(42) {} // error: 'C' does not name a type

看到它在Coliru上失败了。

同样,如果您具有类模板或函数模板,则通常需要将其放在标头中,以便以后可以将其版本标记出来。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM