标头和不同的cpp文件
Headers and different cpp files
我已经知道include guards,但我想解决一些问题:
示例1
Foo.h
int SumOfNums(int i, int j);
Foo.cpp
#include "Foo.h"
int SumOfNums(int i, int j){
return i+j;
}
main.cpp
#include "Foo.h"
#include "Foo.h"
int main(){
SumOfNumbs(5,10);
}
这将编译并运行正常。
示例2
Foo.h
int SumOfNums(int i, int j);
int i;
Foo.cpp
#include "Foo.h"
int SumOfNums(int i, int j){
return i+j;
}
main.cpp
#include "Foo.h"
int main(){
SumOfNumbs(5,10);
}
根据compier对"i"的重新定义。
示例3
Foo.h
int SumOfNums(int i, int j);
enum FooBar{FOO, BAR};
Foo.cpp
#include "Foo.h"
int SumOfNums(int i, int j){
return i+j;
}
main.cpp
#include "Foo.h"
int main(){
SumOfNumbs(5,10);
}
这将编译并运行正常。
示例4
Foo.h
int SumOfNums(int i, int j);
enum FooBar{FOO, BAR};
Foo.cpp
#include "Foo.h"
int SumOfNums(int i, int j){
return i+j;
}
main.cpp
#include "Foo.h"
#include "Foo.h"
int main(){
SumOfNumbs(5,10);
}
根据编译器重新定义FooBar。
综上所述:
示例1-在没有include保护的情况下,为什么Foo.h可以在main.cpp中包含两次?
示例2-int变量与函数头有何不同?
示例3-当Foo.cpp中有一个FooBar定义,main.cpp中又有一个时,链接器为什么不抱怨?
示例4-这与实例1有什么区别?
Ex1-为什么Foo.h可以在main.cpp中包含两次,而没有包含保护?
因为在这种情况下,它只声明一个函数。您可以拥有任意数量的声明。
Ex2-int变量与函数头有何不同?
这也是一个定义,因此打破了一个定义规则。
Ex3-当Foo.cpp和main.cpp中有一个FooBar定义时,链接器为什么不抱怨?
跨翻译单元定义类型很好。
Ex4-这和Ex1之间有什么区别?
您在同一翻译单元中两次定义同一类型-这是不允许的。
-
多次声明函数不是错误。
-
仅
SumOfNums
的函数声明告诉编译器SumOfNums
存在于某个地方(但不存在于此处)。i
的定义在全局区域中分配存储并为其命名。您有两个i
的定义,每个.cpp
文件中都有一个,因为包含该定义的标头包含多次。 -
链接器从未看到
enum FooBar
。编译器将枚举中的值用作常量。 -
此示例包含
enum FooBar
的声明,而示例1没有。编译器只希望看到一次给定enum
的声明。
- 因为函数声明可以重复,但类型定义等不能重复
- 您可以在包括标头的每个翻译单元中定义变量
i
,但"一个定义规则"意味着您在程序中只能对变量有一个定义 enum FooBar
的定义纯粹是类型信息;标头既不定义也不声明该类型的变量。使用<iostream>
这样的标准标头可以得到类似的行为- 这里的区别在于,您试图重复
enum FooBar
的类型定义(通过两次包含Foo.h
),而类型重新定义是不允许的,这也是您应该使用头保护的主要原因
一般的答案是,您可以多次声明内容,但只能定义一次(这并不完全正确,很少有内容可以只声明一次,例如,模板上的默认参数)。当在一个翻译单元中看到多个定义时,编译器会抱怨;当在不同的翻译单元中出现多个事物定义,并且不能在不同的转换单元中多次定义时,链接器会抱怨。例如,类型、模板和内联函数可以在每个翻译单元中定义一次,而不会出现问题。正常函数只能在一个翻译单元中定义。
在第一个示例中,您只需在头中声明一个函数。您可以根据需要随时声明函数。不过,您只能定义它们一次。
您的第二个示例包括变量i
的定义。编译该报头的每个翻译单元将包括i
的定义。当链接器尝试构建东西时,它将检测到i
有两个定义,并且它将失败。包括警卫不会防止这个问题,因为你只能在一个翻译单位内工作。
第三个示例只是在头中声明了一个函数,还定义了一个enum
。类型在每个翻译单元中只能定义一次,但多个翻译单元都可以有一个类型的定义。原因很简单:类型不会创建任何代码,也不会为变量分配任何空间。
您的第四个示例包括两次定义enum
的头,即翻译单元看到类型的重新定义并失败。如果你使用了include防护,这个问题就会被发现。
Ex1-它可以,因为它可以。也就是说,这是合法的,语言中没有任何内容可以阻止您多次包含头文件。如果有的话,一开始就不需要包括警卫。这个Foo.h
中没有任何东西可以阻止它被包含两次。它所拥有的只是一个函数原型,您可以包含任意数量的函数原型副本,只要它们都相同。
Ex2-您将从链接器获得一条重复的符号消息,因为您将有两个名为i
的全局变量。但这是链接器的事情,而不是编译器的事情。如果你真的遇到了编译器错误,我想这可能是因为在Foo.cpp
中,在包含Foo.h
之后,你有一个全局变量i
。但是,在SumOfNums
的主体中,您也使用i
作为函数参数。因此,在该函数中,您无法访问全局i
。不过,并不是所有的c++编译器都会抱怨这一点。有些人只会给你一个警告,然后继续他们愉快的编辑工作。
Ex3-因为FooBar
是一种类型,而不是变量。链接器符号仅为全局变量和函数实现生成(意味着具有实体的函数,而不仅仅是原型)。不存在仅通过包含Foo.h
生成的链接器符号,因此不存在链接器问题。
Ex4-本例中的Foo.h
定义了一个类型,而例1中的CCD29则没有。因此,在同一个main.cpp
文件中包含两次Foo.h
,就是两次注入同一类型定义。这是违法的。如果你问我为什么这对类型定义是非法的,但对函数原型是合法的,我只能告诉你语言规范就是这样写的。这背后可能有一个理由,但我不知道它是什么。
- 为什么两个不同的未命名名称空间可以共存于一个cpp文件中
- 命名空间中具有.h和.cpp文件的类
- 无法编译 rtmidi 测试 cmidiin.cpp 文件, 非法指令
- C++-试图将函数指针推回到另一个CPP文件中的矢量时出错
- 有充分的理由在h文件中使用include保护而不是cpp文件吗
- 如何在cpp文件之间切换窗口?在Qt中
- 在 .h 文件中的类中声明静态变量和在.cpp文件中声明"global"变量有什么区别
- 我有两个类需要在同一 cpp 文件中相互引用,但第一个类无法识别第二个类类型的对象
- .h 和.cpp文件分离时出错,但仅使用 .h 文件时没有错误.我做错了什么?
- 库标题在标题中不可见,但在 cmake build 下.cpp文件中完全可见.为什么?
- C++ 链接到单独的.cpp文件说"multiple definitions"
- 在 cpp 文件中隐藏采用模板参数引用的方法
- 如何使用 samtools C API 构建一个简单的主.cpp文件
- 包含在.cpp文件中包含在 .h 文件时包含
- C++(.cpp文件和.h文件)拆分代码并添加一个函数,提取 - 这很容易吗?
- 在头文件和 cpp 文件中使用一次 #pragma 时出现结构重定义错误
- 如何使用线程类编译 cpp 文件?
- 使用 Powershell 命令将 cpp 文件的文件夹编译为 GNU 的 g++
- 我应该将外部标头放在 .h 文件还是.cpp文件中?
- 从另一个 cpp 文件更改结构内、映射键内的变量