本文解决multiple definition of `XX'的错误。【出于反爬虫的目的,你不是在http://blog.csdn.net/zhanh1218上看到的,肯定不是最新最全的。】

关于头文件的定义中,请一定加上下面代码(此为头文件保护符):

  1. <span style="font-size:14px;"><span style="font-size:12px;">#ifndef PERSON_H_
  2. #define PERSON_H_
  3. // 你的代码块
  4. #endif /* PERSON_H_ */</span></span>

当中PERSON_H_为保护符的名字,一般建议与类名保持一致!样例中我的类名为Person.h。

每当编译器遇到#include时,都要去编译相关代码块,可是编译器不知道是不是已经编译过了,假设编译过了还去编译,那是不是等于代码块写了两次呢?所以,须要有不反复编译的机制,而这个机制正式以上代码。

详细实现为:#ifdef当且仅当变量已定义时为真,#ifndef当且仅当变量没有定义时为真。一旦检測结果为真,则运行兴许操作直至遇到#endif。

也就是说:假设首次include "Person.h",PERSON_H_是未定义,此时,编译器会define这个保护符,并运行代码块的编译!直到遇到#endif。下次遇到这个保护符,就不会运行代码块的编译了。这种机制保证了不会反复编译。

实际使用中,我发现,单个cpp文件里多次include 同一个.h头文件或者头文件里多次include某个头文件,不会有问题。可是,多个cpp文件都include 同一个.h头文件时,这样会出问题。问题是类外定义的非static及非inline函数还是会报multiple
definition of `XX'的错误。【也就是说:#define的作用域仅仅是单个.cpp,而不是全局全部的.cpp文件】

终于解决方法是:仅仅在头文件定义类的申明和类的主体定义(也就是{}内的内容),在一个同名的.cpp文件中定义类外函数的实现!问题完美解决。所以,就算是大神写的书,书上也不全然是对的,或者表述的所有都清楚。

那么为什么头文件能够定义成下面形式呢?而不是仅仅申明,不定义类体呢?

  1. <span style="font-size:14px;"><span style="font-size:12px;">class A
  2. {
  3. // 类定义
  4. };</span></span>

类的定义,仅仅是告诉编译器,类的数据格式是怎样的,实例话后对象该占多大空间。  类的定义也不产生目标代码。因此它和普通变量的声明唯一的差别是不能在同一编译单元内出现多次。

还有一个原因就是,类能够在多个.cpp文件中重定义,变量却不行,除非用extern或者staic修饰的变量。

至于普通变量:同意static型的变量的定义;同意extern申明(不能定义!);直接申明比如int
a; 是不行的,也是多次又一次定义。

extern表明该变量在别的地方已经定义过了,在这里要使用那个变量;static 表示静态的变量,分配内存的时候,存储在静态区,不存储在栈上面。【一篇不错的Blog:点击打开链接

以下是代码演示样例,此实例部分为C++ Primer练习题。【反爬虫,第二天更新代码!】

  1. /*********************************************************************
  2. * file_name: vector_test.cpp
  3. *
  4. * Created on: 2014年6月28日 下午3:34:23
  5. * Author: The_Third_Wave, Blog: http://blog.csdn.net/zhanh1218
  6. * Email: zhanh121823@sina.com
  7. * Last modified: 2014年6月28日 下午3:34:23
  8. *********************************************************************/
  9.  
  10. #include <iostream>
  11. #include <vector>
  12. #include <string>
  13. #include "Headers/Person.h"
  14.  
  15. extern int k;
  16. int main()
  17. {
  18. std::vector<Person> per = {{"The_Third_Wave", 100, "Blog: http://blog.csdn.net/zhanh1218"}}; // 类初始化+vector初始化,所以{{}, {}}必须的
  19. for (auto &p: per)
  20. {
  21. print(std::cout, p);
  22. }
  23. }
  1. /*********************************************************************
  2. * file_name: ddqdq.cpp
  3. *
  4. * Created on: 2014年6月28日 下午10:28:42
  5. * Author: The_Third_Wave, Blog: http://blog.csdn.net/zhanh1218
  6. * Email: zhanh121823@sina.com
  7. * Last modified: 2014年6月28日 下午10:28:42
  8. *********************************************************************/
  9. #include <iostream>
  10. #include <vector>
  11. #include "Headers/Person.h"
  12.  
  13. extern int k;
  1. /*********************************************************************
  2. * file_name: Person.h
  3. *
  4. * Created on: 2014年6月28日 下午11:47:08
  5. * Author: The_Third_Wave, Blog: http://blog.csdn.net/zhanh1218
  6. * Email: zhanh121823@sina.com
  7. * Last modified: 2014年6月28日 下午11:47:08
  8. *********************************************************************/
  9.  
  10. #ifndef PERSON_H_
  11. #define PERSON_H_
  12. /*****************************BEGIN***********************************/
  13. #include <iostream>
  14. #include <string>
  15. using namespace std;
  16. extern int a;
  17. class Person
  18. {
  19. friend istream &read(istream &is, Person &item);
  20. friend ostream &print(ostream &os, const Person &item);
  21. public:
  22.  
  23. Person() = default;
  24. Person(const string &n, unsigned int a, string add):
  25. name(n), age(a), address(add) { }
  26. Person(istream &);
  27.  
  28. string Name() const {return name;}
  29. unsigned int Age() const {return age;}
  30. string Address() const {return address;}
  31.  
  32. private:
  33. string name = "";
  34. unsigned int age = 1;
  35. string address = "";
  36. };
  37.  
  38. inline
  39. Person::Person(istream &is)
  40. {
  41. read(is, *this);
  42. }
  43. /******************************END************************************/
  44. #endif /* PERSON_H_ */
  1. /*********************************************************************
  2. * file_name: Person.cpp
  3. *
  4. * Created on: 2014年6月28日 下午10:55:32
  5. * Author: The_Third_Wave, Blog: http://blog.csdn.net/zhanh1218
  6. * Email: zhanh121823@sina.com
  7. * Last modified: 2014年6月28日 下午10:55:32
  8. *********************************************************************/
  9. #include <iostream>
  10. #include <string>
  11. #include "Person.h"
  12. using namespace std;
  13.  
  14. istream &read(istream &is, Person &item)
  15. {
  16. is >> item.name >> item.age >> item.address;
  17. return is;
  18. }
  19. ostream &print(ostream &os, const Person &item)
  20. {
  21. os << item.name << " " << item.age << " " << item.address << endl;
  22. return os;
  23. }

还有不懂的请留言。

本文由@The_Third_Wave(Blog地址:http://blog.csdn.net/zhanh1218)原创。还有未涉及的,会不定期更新,有错误请指正。

假设你看到这篇博文时发现不完整,那是我为防止爬虫先公布一半的原因,请看原作者Blog。

假设这篇博文对您有帮助,为了好的网络环境,不建议转载,建议收藏!假设您一定要转载,请带上后缀和本文地址。

C/C++:多个.cpp文件包括同一个.h头文件定义方法的更多相关文章

  1. VS Code通过code runner插件编译运行多个cpp文件 | 链接编译.h文件

    1.多个cpp文件在同一级目录 参考:https://jingyan.baidu.com/article/2f9b480d7ceb3d01ca6cc224.html 此时可通过修改Code Runne ...

  2. Cocos2dx3.4 VS2013无法打开包括文件extensions/ExtensionExport.h解决的方法

    本来打算看白鹭引擎的.可是又被叫回来研究新引擎呢,不搞不知道,一搞发现cocos2dx新版本号3.4又有了一些变化. 我查了网上的资源,都没有解决的方法.我如今应该是第一个出这个问题的解决的方法哦.. ...

  3. C语言中头文件和cpp文件解析

    务必提前预读这里的内容:http://www.cnblogs.com/stemon/p/3999844.html 回到cpp文件与头文件各写什么内容的话题上: 理论上来说cpp文件与头文件里的内容,只 ...

  4. c中头文件在cpp文件里引用和.h文件引用的思考

    我们在编敲代码中头文件是常常使用的. 可是头文件是应该包括在.H文件里还是在.cpp文件里.在这个其中有什么样去差别呢. 假如说我们编写了一个a.cpp  .我们将a.cpp文件的变量和函数申明在a. ...

  5. C++中template的.h文件和.cpp文件的问题

    在C++中,用到类模板时,如果类似一般的类声明定义一样,把类声明放在.h文件中,而具体的函数定义放在.cpp文件中的话,会发现编译器会报错.如类似下面代码: //test.h文件 #ifndef TE ...

  6. qt 在ui界面添加控件后在cpp文件中无法调用?

    问题:qt 在ui界面添加控件后在cpp文件中无法调用? 解决方法:在build选项中选择“重新build项目”,再次在cpp中调用添加的控件发现可以调用了. 还有一种情况导致添加控件后无法调用,就是 ...

  7. VS 2010不显示头文件源文件和所有以前分类的文件夹,*.h 和*.cpp都显示在同一个文件

    打开VS后不显示头文件源文件和所有以前分类的文件夹,*.h 和*.cpp都显示在同一个文件 点击右图红色指示显示所有文件夹按钮,就能恢复.

  8. fatal error LNK1169: 找到一个或多个多重定义的符号或多个.c/.cpp文件想同时调用定义在.h文件里面的全局变量,防止重定义变量问题。

    为什么.h文件中不能定义全局变量? 原因: 存在多次创建变量.如果头文件中可以定义全局变量,那么每个包含该头文件的文件里都会有该全局变量的定义.因为C语言的include是直接将文件嵌入到includ ...

  9. h和.cpp文件的区别

    关于头文件和源文件的分别 首先,我们可以将所有东西都放在一个.cpp文件内. 然后编译器就将这个.cpp编译成.obj,obj是什么东西? 就是编译单元了.一个程序,可以由一个编译单元组成, 也可以有 ...

随机推荐

  1. centos7 在 vmware下的安装与配置

    我们这里选择的centos7的版本是  CentOS-7-x86_64-DVD-1511.iso 在vmware下安装,碰到两个问题: 1)安装如下界面时,会发现“开始安装”按钮是灰化的,这时需要对有 ...

  2. [Django实战] 第9篇 - 表单、视图、模型、模板的交互

    本章通过实现一个用户提交任务请求的页面,讲述表单.视图.模型.模板间的交互. 首先,我们需要定义一个表单(forms.py) class CreatetaskForm(forms.Form): cre ...

  3. GitHub学习笔记

    安装 Ubuntu上安装Git sudo apt-get install git Windows上安装Git msysgit是Windows版的Git.从http://msysgit.github.i ...

  4. mysql中怎样查看和删除唯一索引

    mysql中怎样查看和删除唯一索引. 查看唯一索引: show index from mytable;//mytable 是表名 查询结果例如以下: 查询到唯一索引后,怎样删除唯一索引呢,使用例如以下 ...

  5. android-改进&lt;&lt;仿QQ&gt;&gt;框架源代码

    该文章主要改动于CSDN某大神的一篇文章,本人认为这篇文章的面向对象非常透彻,以下分享例如以下可学习的几点: Android应用经典主界面框架之中的一个:仿QQ (使用Fragment, 附源代码) ...

  6. E - Fibonacci Again(找规律)

    逐渐发现找规律的美妙之处啦,真不错,用普通方法解决很久或者很麻烦的问题,找到规律就很方便,算法最主要还是思想 Description There are another kind of Fibonac ...

  7. 根据Email地址跳转到相应的邮箱登录页面 (转)

    //跳转到指定的邮箱登录页面 $(".btn_actemail").click(function () { var uurl = $(".hide_email" ...

  8. 【行业干货】2013中国零售商排名 - 课程公告板 - 京东内部论坛 - Powered by Discuz!

    [行业干货]2013中国零售商排名 - 课程公告板 - 京东内部论坛 - Powered by Discuz! [行业干货]2013中国零售商排名 [复制链接]     bjpanzhoulan   ...

  9. 《UNIX环境高级编程》笔记--sync、fsync和fdatasync函数

    传统的UNIX实现在内核中设有缓冲区高速缓存或页面高速缓存,大多数磁盘 I/O都通过缓冲进行.当将数据写入文件时,内核通常先将该数据复制到其中一个缓冲区中,如果该缓冲区尚未写满,则并不将其排入输出队列 ...

  10. Verilog之case语句

    verilog设计进阶 时间:2014年5月6日星期二 主要收获: 1.学会使用case语句: 2.学会使用随机函数$random. $random: 1.函数说明:$random函数调用时返回一个3 ...