在MFC中,有时需要多个类之间传递信息,一个共通的头文件是个不错的选择。如果在头文件中直接声明一个变量的话,势必会报出一个错误:

  error LNK2005: "struct my_global global_data" (?global_data@@3Umy_global@@A) already defined in MFCApplication1Dlg.obj

  不对呀,我明明是在头文件声明的,不同的文件中的变量应该是同一个啊,怎么还重定义了呢?

  反复查证之后,原来是自己对头文件的理解一直有错误。

  引用一篇好文:http://www.oschina.net/question/253403_44866?sort=time

  摘要部分如下:

  “楼主的问题,是对头文件作用不太了解造成了。头文件本质只是个文本。连源文件都算不上。有些编译器会对.h文件做写特殊化的处理。

  但是希望你理解,.h头 文件自身没有意义,有意义的是#include ,你参考我下面的一个代码例子,不知道你是否能理解,我用C写的,

  C++也基本一样,在使用 #include方面。”

    

//这是一个很简单的程序,就一个main.c函数
#include <stdio.h>
int main(int argc ,char *argv[]){
printf("hello world!\n");
return ;
}
//我把上面修改一下,新生成两个文本文件,printf_hello_world.txt ,return.txt
//printf_hello_world.txt里面的内容就一行
printf("hello world!\n"); //return.txt里面的内容也就一行
return ; //同时修改main.c文件如下
#include <stdio.h>
int main(int argc ,char *argv[]){
#include "printf_hello.world.txt"
#include "return.txt"
}

  "你可以发现,修改后的代码和原始代码运行是一个结果。准确说,对编译器而言,是完全一样的内容。

  #include只是将后面的文件,插入到当前的文本中。其实和.h无关。

  而你将一个函数写在.h里面当多个文件均#include时,则这个函数对于多个文件,再编译器看来,每个文件都存在完全相同的函数

  (只要函数定义 相同就会有冲突)。而C语言或C++,默认对每个函数是可作为外部函数的。此时,连接器就会混乱。究竟连接哪

  个文本(源文件)所编译对应的函数。

  你可以把函数写在头文件里,但需要增加static 前缀。此时这个函数就会在每个#include该头文件的源文件中存在,由于是static,

  对于函数是局部的意思,此时,外部就无法  调用到该函数,最多会出现”找不到该函数的连接错误“而不会说函数重复存在的问题。"

  自然,如果我在头文件中声明变量直接引用的话,就会造成变量重定义的错误。那么该如何正确使用头文件呢?对于函数,我们使用static,对于变量,我们则使用extern。

  具体方法如下:

  在头文件中,添加extern变量:

extern my_global global_data;

  在主对话框中,再次声明该变量:

my_global global_data;

  那么在所有文件中,只要引入头文件,就可以调用该变量了。

  extern的使用是一个基础知识,搞得我昏头昏脑,很是惭愧= = 头文件的正确打开方式则是个意外收获,曰:nice。

MFC学习随笔(2)的更多相关文章

  1. MFC学习随笔(1)

    最近在学习用MFC编写一个简单的界面.其实MFC并不是十分复杂的,经过一段时间的熟悉就可以实现许多基础功能.但是在编写的过程中,经常会遇到林林总总的bug,让人摸不到头脑.今天记录一个过去没有注意过的 ...

  2. MFC 学习之 鼠标移动到Toolbar按钮上显示提示信息(tooltip),状态栏也随之改变

    1.在ResourceView里加入Toolbar资源,命名IDR_TOOLBAR1 2.在主程序的.h文件中加入变量:           CToolBar m_toolbar;CImageList ...

  3. (转) 基于Theano的深度学习(Deep Learning)框架Keras学习随笔-01-FAQ

    特别棒的一篇文章,仍不住转一下,留着以后需要时阅读 基于Theano的深度学习(Deep Learning)框架Keras学习随笔-01-FAQ

  4. C#程序集Assembly学习随笔(第一版)_AX

    ①什么是程序集?可以把程序集简单理解为你的.NET项目在编译后生成的*.exe或*.dll文件.嗯,这个确实简单了些,但我是这么理解的.详细:http://blog.csdn.net/sws8327/ ...

  5. Hive入门学习随笔(一)

    Hive入门学习随笔(一) ===什么是Hive? 它可以来保存我们的数据,Hive的数据仓库与传统意义上的数据仓库还有区别. Hive跟传统方式是不一样的,Hive是建立在Hadoop HDFS基础 ...

  6. JavaScript ES6 数组新方法 学习随笔

    JavaScript ES6 数组新方法 学习随笔 新建数组 var arr = [1, 2, 2, 3, 4] includes 方法 includes 查找数组有无该参数 有返回true var ...

  7. 64位BASM学习随笔(一)

     64位BASM学习随笔(一) Delphi的BASM一直是我最喜爱的内嵌汇编语言,同C/C++的内联汇编相比,它更方便,更具灵活性,由于C/C++的内联汇编仅仅能是或插入式的汇编代码,函数花括号 ...

  8. typeScript学习随笔(一)

    TypeScript学习随笔(一) 这么久了还不没好好学习哈这么火的ts,边学边练边记吧! 啥子是TypeScript  TypeScript 是 JavaScript 的一个超集,支持 es6 标准 ...

  9. MFC学习笔记1---准备工作

    什么是MFC MFC,全称Microsoft Foundation Classes,微软基础类库,顾名思义,是微软的攻城狮们将一些常用的基础的Windows API 函数用C++的形式封装成类,简化程 ...

随机推荐

  1. 记录那些我不清楚的知识点(HTML)

    <div class="link"><a href="http://www.baidu.com/" target="iframeHt ...

  2. iOS.ReactNative-3-about-viewmanager-uimanager-and-bridgemodule

    RCTViewManager and RCTUIManager 1. RCTViewManager 1.1 RCTViewManager 实现了接口RCTBridgeModule @interface ...

  3. MySQL pdo预处理能防止sql注入的原因

    MySQL pdo预处理能防止sql注入的原因: 1.先看预处理的语法 $pdo->prepare('select * from biao1 where id=:id'); $pdo->e ...

  4. [erlang]supervisor(监控树)的重启策略

    1. init函数 init() -> {ok, {SupFlags, [ChildSpec,...]}} | ignore. [ChildSpec,...] 是在init之后默认要启动的子进程 ...

  5. SQL语句性能测试

    /* --Sqlserver 清楚执行缓存, 用于SQL语句性能测试 DBCC DROPCLEANBUFFERS DBCC FREEPROCCACHE */

  6. WampServer3.0.4 允许外网访问配置教程

    原文地址:http://jingyan.baidu.com/album/acf728fd556c93f8e410a344.html?picindex=1

  7. html5新特性之拖放

    1.元素是否可拖动可放置 draggable="true" 设置元素可以拖动 ondragover="allowDrop(event)"  元素默认不能放置,加 ...

  8. hdoj 1869 六度分离

    Problem Description 1967年,美国著名的社会学家斯坦利·米尔格兰姆提出了一个名为“小世界现象(small world phenomenon)”的著名假说,大意是说,任何2个素不相 ...

  9. dhtmlx相关

    主页:http://dhtmlx.com/ 文档地址:http://docs.dhtmlx.com/ 后台:https://dhtmlx.com/docs/products/dhtmlxConnect ...

  10. beanstalkd----协议

    Beanstalkd中文协议 总括 beanstalkd协议基于ASCII编码运行在tcp上.客户端连接服务器并发送指令和数据,然后等待响应并关闭连接.对于每个连接,服务器按照接收命令的序列依次处理并 ...