这里的问题实质是我们在头文件中直接定义全局变量或者函数,却分别在主函数和对应的cpp文件中包含了两次,于是在编译的时候这个变量或者函数被定义了两次,问题就出现了,因此,我们应该形成一种编码风格,即:

    在一个头文件中要想定义一个全局变量,除非我们能够保证这个头文件仅仅只被一个cpp文件包含(也就是main函数所在的那个cpp文件),否则,我们都应该将对应的定义放在这个头文件对应的cpp文件中,仅仅在这个头文件中声明他,这样才能够保证这个变量不被重定义

下面是我找出问题的博客,转载自:C++中重定义的问题——问题的实质是声明和定义的关系以及分离式编译的原理

问题描述如下:

有 三个源文件,A.h、B.cpp、C.cpp。

A.h是头文件,其中声明了三个变量a1、a2、 a3。

B.cpp是A.h中所声明的类的实现源代码,C.cpp是主程序文件。B.cpp和C.cpp中均包含头文件 A.h。

在编译时,编译能够通过,但链接时出了问题,出现”error   LNK1169:   找到一个或多个多重定义的符号“的错误。

经过分析,确定了这是由于两个实现文件中重复包含了头文件而造成的。可解决方法却始终找不到。

要 注意的是,在这里,在头文件中加入#ifndef……#endif这样的预编译命令是没用的,因为这是防止嵌套包含头文件的,而本例中并没有嵌套包含,是 在两个文件中分别包含。

因为这三个变量在两个实现文件中都要用到,所以一定要包含在A.h中。后来在网上找到了解决方法,其实很简单。

就是在A.h中的三个变量声明前加上extern 关键字,然后在B.cpp中不加extern关键字再次声明这三个变量。于是编译链接顺利通过。

其实这是C++中比较基础的问题。
还有种情况是定义了函数,但在另个文件中准备用#include打开,但是结果还是会出现。

直接包含不就在两个cpp文件中都定义了相同的函数/变量吗,链接时会出现重复定义(你自己试试),所以需要使用extren申明一下即可,他们使用的是同一个实体。

例如:

1、你在a.cpp中定义了一个函数
void func()
{
}

希望在b.cpp中调用,调用前就需要进行声明,格式如下:
extren void func(); //extren 后面根的形式和函数定义形式要完全相同

void mian()
{
    func();
}

2、1、你在a.cpp中定义了一个变量  int a;

希望在b.cpp中使用,使用前就需要进行声明,格式如下:
extren int a; //extren 后面根的形式和变量定义形式要完全相同

void main()
{
    int b = a;
}

C++中重定义的问题——问题的实质是声明和定义的关系以及分离式编译的原理的更多相关文章

  1. 变量声明和定义及extern 转载

    在讨论全局变量之前我们先要明白几个基本的概念: 1. 编译单元(模块):    在IDE开发工具大行其道的今天,对于编译的一些概念很多人已经不再清楚了,很多程序员最怕的就是处理连接错误(LINK ER ...

  2. C++将模板的声明和定义放置在同一个头文件里

    1. 一个类: 头文件用于保存类的声明:定义文件保存类的实现.   2. 分离编译模式: 允许在一个编译单元(.cpp文件)中定义函数.类型.类对象等,然后在另一个编译单元中引用它们.编译器处理完所有 ...

  3. kvm中重命名虚拟机

    kvm中重命名虚拟机 1.查看虚拟机 [root@linux ~]# virsh list --all Id Name State ---------------------------------- ...

  4. 在源文件(.c)和头文件(.h)中声明和定义的区别——C语言

    最近在看多文件编程的时候遇到的一个问题,本来以为理解了声明和定义的区别(然而并没有····),也算是重新认识了一次声明和定义,下面上代码 情形一:在源文件(.c)中 相信大部分读者对声明和定义的理解是 ...

  5. C++中全局变量的声明和定义

    原文链接:http://blog.csdn.net/candyliuxj/article/details/7853938 (1)编译单元(模块) 在VC或VS上编写完代码,点击编译按钮准备生成exe文 ...

  6. C\C++中声明与定义的区别

    声明和定义是完全同的概念,声明是告诉编译器"这个函数或者变量可以在哪找到,它的模样像什么".而定义则是告诉编译器,"在这里建立变量或函数",并且为它们分配内存空 ...

  7. C/C++中的声明与定义

    含义 声明(Declaration), 用于告诉编译器被声明的函数/变量的存在, 及它们的类型/调用格式信息, 以检查是否被正确调用. 声明不分配内存空间. 定义(Definition), 用于告诉编 ...

  8. zend studio中ctrl+鼠标左键无法转到类或函数定义文件的解决方法

    转载自:http://blog.csdn.net/wide288/article/details/21622183 zend studio中ctrl+鼠标左键无法转到类或函数定义文件的解决方法: ze ...

  9. solr与.net系列课程(八)solr中重跑索引的注意事项

    solr与.net系列课程(八)solr中重跑索引的注意事项 我们如果在项目中使用solr,那肯定就是把数据库中的数据跑进solr服务器中,solr有两种操作一种是新建索引,一种是增量索引,这里我们来 ...

随机推荐

  1. R语言:常用统计检验

    统计检验是将抽样结果和抽样分布相对照而作出判断的工作.主要分5个步骤: 建立假设 求抽样分布 选择显著性水平和否定域 计算检验统计量 判定 -- 百度百科 假设检验(hypothesis test)亦 ...

  2. Mac入门(三)使用brew安装软件

    brew 又叫Homebrew,是Mac OSX上的软件包管理工具,能在Mac中方便的安装软件或者卸载软件, 只需要一个命令, 非常方便 brew类似ubuntu系统下的apt-get的功能 阅读目录 ...

  3. webstorm官网最新版激活:

    2016.2.3版本的破解方式:目前最新的就是2.3版本,在打开的License Activation窗口中选择"activation code",在输入框输入下面的注册码:3B4 ...

  4. iOS之数字的格式化

    //通过NSNumberFormatter,同样可以设置NSNumber输出的格式.例如如下代码: NSNumberFormatter *formatter = [[NSNumberFormatter ...

  5. no identity found Command /usr/bin/codesign failed with exit code 1 报错解决方法

    stackoverflow 的解决方法是 xcode->preference->account->view detail -> refresh the provisioning ...

  6. iOS中NSLog输出格式大全

    iOS开发中的输出格式大全: %@                   对象 %d, %i               整数%u                    无符整形%f           ...

  7. 随机生成长度为len的密码,且包括大写、小写英文字母和数字

    一道华三面试题,随机生成长度为len的密码,且包括大写.小写英文字母和数字,主要Random类的使用,random.nextInt(len)表示生成[0,len)整数.具体实现见下面代码,已经很详细了 ...

  8. 关于Oracle的疑问

    索引范围扫描(index range scan) select empno,ename from emp where empno > 1 order by empno 这种情况下不会使用索引范围 ...

  9. 分布式一致性算法--Raft

    前面一篇文章讲了Paxos协议,这篇文章讲它的姊妹篇Raft协议,相对于Paxos协议,Raft协议更为简单,也更容易工程实现.有关Raft协议和工程实现可以参考这个链接https://raft.gi ...

  10. Java实现上传下载

    一.上传 二.下载 import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.Fi ...