头文件与源文件

以下内容全部是个人总结,如果有错误请指正!

在初学C++的时候,我总是彷徨于不恰当使用头文件、声明、定义、源文件而导致的各种Link错误。今天我想通过一些简单的测试,得到一些概括的,一般性的结论。(因为我没有学习过C++的编译器,所以我所以这些结论仅仅是一些根据一些现象的猜想)

实验环境:集成开发环境(Visual Studio 2017),并没有直接使用过g++的shell命令。

1. 在Visual Studio 2017 环境下,项目中的文件会被赋予不同的类型每个类型有各自的作用。

1.1 头文件

  头文件不会参与Link过程,所以头文件中如果存在语法错误,是不会被发现的。

e.g:

在头文件文件夹下新建文件:输入“wrong code”。运行 源.cpp,发现正常运行。

1.2 源文件

  源文件既可以被 #include 导入(因为头文件源文件类型的区分是VS的限定,但对于一个编译器来说任何文件都是没有区别的,只有输入的参数不同),但导入之后同样会编译自身之后Link。

e.g:

在源文件文件夹下新建文件a.h: 定义函数 a, 在源.cpp 中include该文件,并使用a函数。

系统将出现符号重定义的错误:因为 VS认为a.h是源文件故编译了他。而源.cpp中include的部分也被编译,故出现了两个相同的符号。

2. C++ 的 #include 对文件的名字(后缀)不敏感

2.1 可以使用无 .h 后缀的文件作为 #include 的目标

  这个是一个不需要实验的结论,因为常用的#include <iostream>便是一个很好的例子。

2.2 如果把一个正常的 .h 文件改成 .cpp 后缀,效果是一样的



正常情况:

// 源.cpp#include "A"
#include <iostream>

int main() {
    A a;
    //int main2();
    std::cout << "在main里:" << a.value << std::endl;
    //std::cout << "在main里:" << a.value << "  " << a.functionA() << std::endl;
    //std::cout << "在main2里:";
    //main2();
    getwchar();
    return 1;
}
// A#pragma once
class A
{
public:
    int value = 100;
    //A();
    //~A();
    int functionA();

private:

};

正常输出



当 #include 的对象改为 .cpp 后缀

// 源.cpp#include "A.cpp"
#include <iostream>

int main() {
    A a;
    //int main2();
    std::cout << "在main里:" << a.value << std::endl;
    //std::cout << "在main里:" << a.value << "  " << a.functionA() << std::endl;
    //std::cout << "在main2里:";
    //main2();
    getwchar();
    return 1;
}
// A.cpp#pragma once
class A
{
public:
    int value = 100;
    //A();
    //~A();
    int functionA();

private:

};

正常输出

3. #include 是的本质是将 #include文件的全体代码替换到当前位置

3.1 (猜想)因为 #include 带 “#” 所以是预处理过程,其过程将先与其他语法检查步骤



使用 #include 语句

// 源.cpp#include "testInclude.h"
#include <iostream>

int main() {

    std::cout << functionToTestInclude();
    getwchar();
    return 1;

}
// testInclude.h#pragma once

int functionToTestInclude() { return 1; }

正常输出



直接将 #include 对象替换掉 #include 语句

// 源.cppint functionToTestInclude() { return 1; }
#include <iostream>

int main() {

    std::cout << functionToTestInclude();
    getwchar();
    return 1;

}

正常输出

结论:

1. 替换后效果一样。

2. 没有检测出“未定义函数”,说明语法检测过程是在 #include 之后。

3. 所以现在 “#include 的文件” 也没有必要讨论了。我们所讨论的项目里剩下的,#include 别的文件的文件,并默认在 #include 展开之后,这些文件就是Visual Studio 2017里标记类型为源文件的需要被编译的文件。

4. 单个文件内支持多次全局声明

4.1 多个文件支持重复全局声明

  const部分

  C++中的声明与定义


// 源.cpp// 声明函数
int functionToTestInclude();
int functionToTestInclude();
int functionToTestInclude();

// 声明变量
extern int intV;
extern int intV;

// 声明函数指针
int *intFP();
int *intFP();

class classExample;
class classExample;

// 正常运行
int main() {

    return 1;

}
// 源1.cpp//声明函数
int functionToTestInclude();
int functionToTestInclude();
int functionToTestInclude();

//声明变量
extern int intV;
extern int intV;

// 声明函数指针
int *intFP();
int *intFP();

class classExample;
class classExample;

5. 单个文件中不允许任何全局数据重复定义,只有类允许在多个文件中重复定义(包括类内方法定义,但不包括类外部实现的方法)

5.1 使用函数时,可以先声明,编译器会自动查找到函数的定义(在后文或其他文件内)。

5.2 定义对象时,必须在之前上文中有类的定义。

#include "iostream"

class testClass;
class testClass
{
};
int function();

int main() {

    testClass as;
    int ret = function();
    getchar();
    return 1;

}// 函数在后文定义不会出现问题
int function() { return 1; }
// 将testClass的定义 替换到此处,将导致程序非法,出现 “testClass”未定义的错误。

5.3 定义类时,如果需要某个其它类构造器内部的属性或方法,可以不用定义,声明即可,但必须在同一文件内。

#include "iostream"

class testClass;
class refClass;
class testClass
{
public :
    refClass ref_class;
};

int main() {

    testClass as;
    getchar();
    return 1;

}
int function() { return 1; }
// 先声明,在后文定义不会出现问题 (若将此定义移至其他文件,将会出现“refClass未定义”的错误)
class refClass
{

};

5.4 多个文件重复定义类,构造对象时所选用的类定义是不确定的。

5.4.1 因为一般情况类写在头文件内,所以每个文件 include 展开后类的定义是相同的,故不会出现问题。



头文件与源文件

时间: 2024-10-25 02:34:07

头文件与源文件的相关文章

C/C++编程 头文件与源文件中的内容

从规模较小的程序转到比较复杂的程序,头文件与源文件中的内容组织困扰了很久,特别是头文件中该放哪些内容,到处搜索文章并进行了一次总结,如果有什么错误或者值得商榷的地方,希望大家能够不吝赐教. 引入问题: 编译模式:一个程序的源代码,可以放到不同的文件进行存放,每一个源文件都是独立的,可以分别进行编译,生成程序的时候只需要将各个目标程序进行一次连接便可以了.比如在一个文件中定义了一个函数 void a(),而另外一个文件中只有void a()的声明,如此并不影响把这个文件编译成目标文件,当一个文件中

Visual Studio 中的头文件、源文件和资源文件都是什么?有什么区别??

头文件:后缀为.h,主要是定义和声明之类的,比如类的定义,常量定义源文件:后缀.cpp,主要是实现之类的,比如类方法的实现资源文件主要是你用到的一些程序代码以外的东西,比如图片之类,或者菜单.工具栏之类的定义之类

C++中头文件与源文件的作用详解

一.C++ 编译模式 通常,在一个 C++ 程序中,只包含两类文件―― .cpp 文件和 .h 文件.其中,.cpp 文件被称作 C++ 源文件,里面放的都是 C++ 的源代码:而 .h 文件则被称作 C++ 头文件,里面放的也是 C++ 的源代码. C++ 语言支持"分别编译"(separatecompilation).也就是说,一个程序所有的内容,可以分成不同的部分分别放在不同的 .cpp 文件里..cpp 文件里的东西都是相对独立的,在编译(compile)时不需要与其他文件互通

头文件与源文件中都分别存放哪些东西

    在C代码文件中,我们经常会看到两类文件:                                         一类是:".h"文件                                         一类是:".c"文件    ".h"文件,就是我们常说的头文件.    ".c"文件,就是我们常说的源代码文件.      而在做开发的时候,经常不知道要把哪些东西放到".h"文

C++笔记--建立头文件与源文件

新建一个头文件 myadd.h #ifndef MYADD_H #define MYADD_H int fun_add(int a,int b); #endif 新建一个源文件 myadd.cpp #include "myadd.h" int fun_add(int a,int b) { return a+b; } 主程序: #include <iostream> #include "myadd.h" using namespace std; int m

设计自己的头文件

头文件一般包含1.类的定义,2.extern变量的声明, 3.函数的声明: 规则1: 头文件是用于声明的,而不是用于定义: 下面语句不应该出现在头文件中: extern int val = 10; //虽然加了extern关键字,但这仍是一个定义,因为对val进行了初始化赋值: double fica_rate; //这也是一个定义:定义了一个double型变量fica_rate, 为fica_rate分配了内存空间: 正确写法: extern doublefica_rate; extern i

预处理命令(宏定义,条件编译,头文件)

宏定义 <1>不带参数宏定义:#define PI 3.1415926 <2>带参数的宏定义: #define PI  3.1415926 #define S(r)  (PI*(r)*(r)) void main(){float  a=2,area;area=S(a); } 用宏可以得到几个结果: #define CIRCLE(R,L,S,V)  L=2*PI*(R);S=PI*(R)*(R);V=4.0/3.0*PI*(R)*(R)*(R) void main(){float r

头文件声明

一,问题提出: class B; class A { public: B b; }; class B { public: A a; }; 以上写法会造成头文件相互包含,是错误的. 因为在A对象中要开辟一块属于B的空间,而B中又有A的空间,是一个逻辑错误,无法实现的. 我们只需要把其中的一个A类中的B类型成员改成指针形式 就可以避免这个无限延伸的怪圈了. 为什么要更改A而不是B?因为存在先后顺序问题-->因为C++编译器自上而下编译源文件的时候,对每一个数据的定义,总是需要知道定义的数据的类型的大

函数实现不放在头文件的原因,及何时可以放头文件的情况

1 .引子       在平常的 C/C++ 开发中,几乎所有的人都已经习惯了把类和函数分离放置,一个 .h 的头文件里放声明,对应的 .c 或者 .cpp 中放实现.从开始接触,到熟练使用,几乎已经形成了下意识的流程.尽管这样的做法无可厚非,而且在不少情况下是相对合理甚至必须的,但我还是要给大家介绍一下把实现全部放置到头文件中的方式,给出可供大家使用的另一个选择.同时针对这一做法,也顺便说一下其优缺点以及需要注意的情况.       我是一个很喜欢简洁的人,多年以来甚至养成了这样的癖好,如果一