标题:关于头文件
只看楼主
lonmaor
Rank: 16Rank: 16Rank: 16Rank: 16
来 自:郑州
等 级:版主
威 望:75
帖 子:2637
专家分:6423
注 册:2007-11-27
得分:0 
Folder&表示返回的是一个类类型的引用,就跟int&一样。
Folder::operator=表示operator=归属于Folder类的,是一个重载的成员函数。这里是类作用域标识符。

从不知道到知道,到知道自己不知道,成长的道路上脚步深深浅浅
2012-08-23 16:35
pangding
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:北京
等 级:贵宾
威 望:94
帖 子:6784
专家分:16751
注 册:2008-12-20
得分:0 
1.书上在说完  以防重复定义所以头文件只声明   后,就讲了条件预处理命令。两者是   并列关系  即  是两种处理 多次定义  的方法?
    两者相辅相成吧。还是用例子可能说得清楚些:
程序代码:
/* a.h */
#ifndef A_H
#define A_H

#include <iostream>

int a = 1;

#endif
程序代码:
/* b.h */
#ifndef B_H
#define B_H

#include <iostream>

int a = 1;

#endif
程序代码:
#include "a.h"
#include "b.h"
using namespace std;

int main()
{
    cout << a << endl;

    return 0;
}
    虽然,两个头文件都使用了条件编译,但还是不能避免重定义。
    不过它有另外的一些好处。比如如果 iostream 这个头文件也使用了这个技术的话(确实使了),本来可能会展开两次的的头文件,就只展开了一次。这意味着编译器可以少分析数千行的代码(这还得假设重复包含不会出现其它问题)。

    另一方面,如果 a.h 和 b.h 里都用的是外部声明。而其实 a 这个变量是定义在比如 a.c 这个文件里的话。那么包多少遍 a.h 和 b.h 都没问题。当然了,如果你又写了一个 b.c 也定义了 a 可能还是不行。

2.“contents 其实只是类 screen 定义的一部分。”是说类定义里的对变量的操作都不是定义?是声明?那怎么还会“因为如果一个变量既在 a.h 中有所定义,又在 b.h 中有所定义。那么最终会因为重复定义而产生错误。所以一般只能用 exterm 声明变量,而在对应的 cpp 中定义。”?   没理解,所以这两句意思感觉矛盾。。。   “变量应该定义在 cpp 里。”到底怎么定义呢?
    假如写 class A {}; 那么,无论你在那个括号里写什么东西,都是类 A 的定义,类的定义就是比较长而已。虽然有些语句看上去像是在定义变量,但其实都不是在定义变量。而是在定义一个类的成员,只是类定义语句的一部分。类的定义只能放在 .h 里,原因昨天我有解释,这不重复了。又果有什么不明白的地方可以再问。
    而后半段说的其实是上面那个问题。当时可能语序搞的不是很清楚,引起了一些歧义。正确的写法就是头文件里写 extern int a; cpp 里写 int a = 1; 这样。类的定义不受这个限制。

3“.vs2010的项目有个include属性。。。这些是路径?
4.“你可以进入命令行窗口后打set回车。。。怎么没呢?
    见 L版 的解释。

5但“一些指定的地方”是?我是可以随便在一个工程里建一个定义函数的cpp吗?只要有,他就能找到是吗?
    “一些地方”指的就是像 include 一样,你设置的地方。你不告诉它哪找,它自己是不会自动搜索整个硬盘的。如果你指定的地方它找不到,它就认为是找不到了。
    如果你没指定过,其实就是用的默认的,一般就是库文件,和当前工程。如果你指定它到另一个地方去找(这种做法有点像指定了另一个地方也是库文件一样),vc 应该是可以正确链接并生成可执行文件的。只是一般习惯上可能还是把相关的东西拉到当前工程里。我没怎么用过 vc,所以不是很清楚 vc 的做法。

感觉函数定义什么的就可以直接写在头文件里也没事了吧,那为何还要建源文件?
    最重要的,一个头文件可能不止插到一个源代码里。和重定义变量一样,比如 a.h 里定义了一个函数 func(),而 main.cpp 和 src.cpp 都包含了 a.h,那么 func 这个函数就会被定义两次。编译也许可以过,但会引发链接错误。
    不过这么做还涉及别的考虑。人们普遍意识到,代码版本升级等行为,一般都会对函数的实现做出改动。但函数的原型却很少改动。这即是说,函数的原型比函数的实现更稳定。
    把稳定的东西插入到另一段代码里或者给其他人看是合适的。而把经常可能会改动的东西给别人看就不太好。因为人们一但知道某个函数是如何实现的,可能潜意识就会或多或少地利用这个函数的实现机里写自己的代码。但之后实现变了,也不会通知这个人,这个人也可能之后没再看过升级后的实现了。这就可能使得他写的代码兼容性下降。
    把定义写在源文件里还有其它效率上的原因,比如在编译时,编译器会分析代码的逻辑。比如我有 100 个源文件,我只改动了其中的三个后,要求重新构建。这时如果某个代码本身没有发生过任何变化,而且它包含的所有头文件也没有发生过变化。那么这些代码本质上就没有发生任何变化,因此没有重新编译的必要。只用重新编译那三个改动了的代码,再把这些重新编译后的东西链接回原来的代码里就行了。如果你动不动就要改头文件,那么所有包含这些头文件的代码,虽然代码本身没有变化,但由于原来在头文件里声明的东西有可能会发生变化,编译器无法确定这些变化会有哪些影响,只好把它们全都重新编译一遍。

   
如Folder类定义前写一个Message的声明,不就解决了循环包含吗?
    这种技术叫做 forward declaration,也许可以译做提前声明。是不完整声明的一种。这种声明是有限制的。如果一个类在声明的过程中,需要知道另一个类的存在,而不需要定义这个类的对象,也不需要知道这个类的任何细节。就可以用这个语法项。
    具体讲,提前声明的类型只能用于声明其它的内容,但不能用于定义任何和它自己有关的东西。比如可以用这个方法声明友元类:
程序代码:
class A;    // forward declaration.

extern A a;    // OK; 声明一个外部对象。只是声明没有问题,没有定义。
class B { friend class A; };    // OK; 声明一个友元类,只要知道 A 是个类就行了。
class C { A *pa; };    // OK; 声明一个指向 A 类的指针。这个有点难理解,因为毕竟这里定义了一个对象,但是只用到了指向 A 的指针,没有用到和 A 有关的任何细节。
class D { A a; };    // error; 定义与 A 有关的对象。不行。

int main()
{
    return 0;
}
因此这种语法无法实现循环包含的情况。没有任何方法能实现循环包含。因为先定义的那个类,无法看见另一个类的定义,从而无法定义和那个类有关的任何对象。

还有为什么返回值类型Folder&前没有Folder::
    返回值前不需要加 Folder::,因为编译器在这之前看见过 Folder 的定义了,知道 Folder,或者  Folder& 是什么。那个 Folder::operator= 是用来限定这个函数名的。L版 回答的很清楚。
    其实可以把 Folder::operator= 看成是这个函数的全名。在类内部使用函数时,默认就是用本类内部的函数,可以省去。在外面的时候就必须得加上了。注意成员函数定义在类的外面,因此要加 :: 限定。如果是在外面调用,那要用 f.operator= 类似的语法,因为编译器知道 f 是 Folder 的一个对象,才知道你要调用的是这个类的 operator= 而不是其它的。


[ 本帖最后由 pangding 于 2012-8-23 23:20 编辑 ]
2012-08-23 23:10
pangding
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:北京
等 级:贵宾
威 望:94
帖 子:6784
专家分:16751
注 册:2008-12-20
得分:0 
楼主好学,而且显然是自己动脑筋了。回答这种人问的问题,细致点不浪费。
2012-08-23 23:11
TonyDeng
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:304
帖 子:25859
专家分:48889
注 册:2011-6-22
得分:0 
以下是引用pangding在2012-8-23 23:11:36的发言:

楼主好学,而且显然是自己动脑筋了。回答这种人问的问题,细致点不浪费。

带女人头的当然要细致点啦

授人以渔,不授人以鱼。
2012-08-23 23:13
pangding
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:北京
等 级:贵宾
威 望:94
帖 子:6784
专家分:16751
注 册:2008-12-20
得分:0 
以下是引用TonyDeng在2012-8-23 23:13:11的发言:


带女人头的当然要细致点啦

这层原因戳破了就没意思了
2012-08-23 23:18
humy
Rank: 2
等 级:论坛游民
帖 子:69
专家分:18
注 册:2012-7-23
得分:0 
回复 12楼 pangding
“正确的写法就是头文件里写 extern int a; cpp 里写 int a = 1; 这样。类的定义不受这个限制。”
恩。。。。关于声明,定义。int  a;是定义吧?那在类的定义里写,还是定义不?如:class A{ int a;}中的算是声明?如果是定义,可大家都这么些的啊。。
谢谢
2012-08-25 17:53
pangding
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:北京
等 级:贵宾
威 望:94
帖 子:6784
专家分:16751
注 册:2008-12-20
得分:0 
class A{ int a;}中的算是声明?
这个语句比较长,但只定义了一个类 A,它包含了一个属性为 private,类型为 int 的成员,名为 a。
类定义的语法形式是 class A { ... }; 大括号里的看成整体先不算,它只有一个分号。因此和 int a; 是一样的。不管类的定义多长,都只是一条语句。这么说明白了?
编译器在定义任何类 A 的对象之前,必须见到类 A 的完整定义,否则它还是不知道类 A 的的细节。因此如果不把类 A 的完整定义写在 .h 里是没有用的,编译器无法从其它文件中查到。

我这么说吧,合理的做法是这样,任何对象都只在 .cpp 中定义,而在 .h 中声明。至于为什么这样做合理,之前我分析过了,应该你也有所明白了。
但类的定义不属于这个范畴。因为类的定义,其实是在告诉编译器一个类型,而不是在声明对象。相当于我在告诉编译器 int 是什么东西。这不定义任何对象,只是定义这么一个概念。当然了 int 是内置的基本类型,这个“内置”就是指,它已经知道了,不用你教。但类是你自己脑子中的东西,需要有一种严格的语法来教会编译器。这个语法就是类定义。而一旦你类定义好了,就可以用这个类的概念定义对象了,比如和 int i; 一样,现在也可以写 A a; 了。这两个语句所谓的定义是对等的概念,必须要放在 cpp 里。而“定义”类这个所谓的定义,是一种观念上的东西,与实际的定义不同。


[ 本帖最后由 pangding 于 2012-8-27 01:27 编辑 ]
2012-08-27 01:26
humy
Rank: 2
等 级:论坛游民
帖 子:69
专家分:18
注 册:2012-7-23
得分:0 
回复 17楼 pangding
恩。。谢谢。。其实我想问的是class A{int a;};中对于a 这个变量是定义还是对a的声明。。。
2012-08-27 08:24
TonyDeng
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:304
帖 子:25859
专家分:48889
注 册:2011-6-22
得分:0 
以下是引用humy在2012-8-27 08:24:25的发言:

恩。。谢谢。。其实我想问的是class A{int a;};中对于a 这个变量是定义还是对a的声明。。。

那是占位,就如struct A { int a; };一样。其实,class和struct在原理上是相同的,通常视struct为没有函数的class,事实上,C++的class概念就是从struct中引申出来的,所以到现在,基本上都用class取代struct了。

授人以渔,不授人以鱼。
2012-08-27 08:42
pangding
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:北京
等 级:贵宾
威 望:94
帖 子:6784
专家分:16751
注 册:2008-12-20
得分:0 
以下是引用humy在2012-8-27 08:24:25的发言:

恩。。谢谢。。其实我想问的是class A{int a;};中对于a 这个变量是定义还是对a的声明。。。
看来我还是没说清楚。
这个语句既没有声明变量 a,也没有定义变量 a。它根本不是一个独立的语句,只是类 A 定义中的一小部分。不过长的有点像一个声明语句。

另外在从概念上讲,所有的变量定义都是变量声明。声明是个更广泛的概念,其中会引发内存分配的声明语句称作变量定义。
2012-08-27 12:41



参与讨论请移步原网站贴子:https://bbs.bccn.net/thread-379925-1-1.html




关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.091669 second(s), 7 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved