关于头文件
更新日期:
文章目录
1. 定义函数必须指定四个元素:返回类型、函数名、圆括号里面的形参(可能为空)和函数体(以花括号开始并以花括号结束的语句块)。
2. main函数的返回值是一个状态指示器,通常返回0,表示main函数成功执行完毕。
3. 大多数情况下学习语言之前要先学习IDE,其实从简单的命令行开始学习可能更容易些。
4. 源文件由文件名和文件后缀组成。
3. 大多数情况下学习语言之前要先学习IDE,其实从简单的命令行开始学习可能更容易些。
4. 源文件由文件名和文件后缀组成。
C++用命名空间来管理类,函数,以及其他的成员。
using namespace std;是使用标准命名空间下的成员。
using namespace std;是使用标准命名空间下的成员。
如果采用VC++6.0现在学习編程序会不会有点out了呢?
也不会。不过会遇到一些障碍,比如Win7可能不能很好地运行VC6,然后VC6里的C++与C++的标准的距离比较远,有些东西甚至可能是相反的。
main.cpp是怎么知道ticketmachine.cpp中对类的定义的?
知道是通过头文件,使用是通过链接
表示用命令运行,对不熟悉Linux和Mac的人来说,很困难,所以还是用eclipse编译器好。
但是要真正了解编译、链接过程,还是命令行运行更直观。用IDE不太好讲清楚,有时候太自动化的东西忽视了很多内在的细节,受益匪浅!IDE帮我们做的事情太多了,命令行则不会。初学者可以用IDE,进阶以后就可以用命令行了解深层的东西了。
u@macbook c++$ more a.h
void f(); //declaration
int global; //definition
u@macbook c++$ more a.cpp
#include "a.h"
int main(){
return 0;
}
u@macbook c++$ cpp a.cpp
# 1 "a.cpp"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "a.cpp"
# 1 "a.h" 1
void f();
int global;
# 2 "a.cpp" 2
int main(){
return 0;
}
u@macbook c++$ g++ a.cpp –save-temps
u@macbook c++$ ls -l
-rw-r–r– 1 u staff 40 8 11 11:17 a.cpp
-rw-r–r– 1 u staff 23 8 11 19:08 a.h
-rw-r–r– 1 u staff 136 8 11 19:40 a.ii
-rw-r–r– 1 u staff 1144 8 11 19:40 a.s
-rw-r–r– 1 u staff 660 8 11 19:40 a.o
-rwxr-xr-x 1 u staff 8680 8 11 19:40 a.out
ii编译预处理指令结束之后的结果
s汇编代码
o目标代码
out最终可执行的程序
u@macbook c++$ more a.ii
# 1 "a.cpp"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "a.cpp"
# 1 "a.h" 1
void f();
int global;
# 2 "a.cpp" 2
int main(){
return 0;
}
编译器拿到的是这样一个文件,经过编译预处理指令把头文件超进来,形成一个大的文件,这个大的文件拿给C++编译器做编译,所以include做的就是文本的插入
u@macbook c++$ more b.cpp
#include "a.h"
void f(){
}
u@macbook c++$ g++ a.cpp b.cpp
duplicate symbol _global in:
/var/folders/x6/_8nknfgs6px6s20_n2qq4hq40000gn/T//ccKZiIGm.o
/var/folders/x6/_8nknfgs6px6s20_n2qq4hq40000gn/T//ccjzfGwP.o
ld: 1 duplicate symbol for architecture x86_64
collect2: ld returned 1 exit status
u@macbook c++$ g++ a.cpp b.cpp –save-temps
duplicate symbol _global in:
a.o
b.o
ld: 1 duplicate symbol for architecture x86_64
collect2: ld returned 1 exit status
u@macbook c++$ ls -l
-rw-r–r– 1 u staff 40 8 11 11:17 a.cpp
-rw-r–r– 1 u staff 23 8 11 19:08 a.h
-rw-r–r– 1 u staff 136 8 11 20:19 a.ii
-rw-r–r– 1 u staff 660 8 11 20:19 a.o
-rw-r–r– 1 u staff 1144 8 11 20:19 a.s
-rw-r–r– 1 u staff 29 8 11 20:01 b.cpp
-rw-r–r– 1 u staff 124 8 11 20:19 b.ii
-rw-r–r– 1 u staff 644 8 11 20:19 b.o
-rw-r–r– 1 u staff 1066 8 11 20:19 b.s
有.ii说明编译预处理已经过了,有.o说明编译已经完成了,.CPP已经编译得到了它对应的.O文件编译已经完成了,接下来要做的事情是(我们知道编译的顺序是.CPP->.II->.S->.O->.OUT,有一个编译预处理指令把它变成了.II,有一个编译器把它变成了.S,有一个汇编器把.S变成了.O,连汇编都做完了,到最后一步要把A.O和B.O联在一起,生成A.OUT的时候出错了,这个事情是由谁在做呢就是这个ld(linked)这是连接器,它在连接的时候发现在A.O和B.O里面都有一个叫做global的东西是重名的,这个是不可以的)
u@macbook c++$ more a.ii
# 1 "a.cpp"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "a.cpp"
# 1 "a.h" 1
void f();
int global;
# 2 "a.cpp" 2
int main(){
return 0;
}
u@macbook c++$ more b.ii
# 1 "b.cpp"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "b.cpp"
# 1 "a.h" 1
void f();
int global;
# 2 "b.cpp" 2
void f(){
}
可以看出来编译的时候是没有问题的,编译的时候为什么没有问题?大家都知道编译器在编译的时候都是针对一个编译单元的,就是针对一个源代码文件来进行编译的,它在编译a.cpp的时候它不知道还有b.cpp存在,在编译b.cpp的时候也不知道a.cpp的存在,它只针对一个c++单元进行编译编译完之后当然没有问题,在它一个里面是正确的,但是想把他们放在一起的时候出现问题了
我们怎么避免这个问题呢?
我们需要把definition变成declaration,怎么设置一个全局变量的declaration呢,需要一个关键词extern
u@macbook c++$ more a.h
void f();
extern int global;
u@macbook c++$ more a.cpp
#include "a.h"
int main(){
return 0;
}
u@macbook c++$ more b.cpp
#include "a.h"
void f(){
global ++;
}
u@macbook c++$ g++ a.cpp b.cpp –save-temps
Undefined symbols for architecture x86_64:
"_global", referenced from:
f() in b.o
ld: symbol(s) not found for architecture x86_64
collect2: ld returned 1 exit status
有问题的地方,在b.cpp中定义没有赋值依然可以编译通过,但按照老师讲的是是由
u@macbook c++$ more a.h
void f();
extern int global;
u@macbook c++$ more b.cpp
#include "a.h"
int global;
void f(){
global ++;
}
u@macbook c++$ more a.cpp
#include "a.h"
int main(){
return 0;
}
u@macbook c++$ g++ a.cpp b.cpp –save-temps
u@macbook c++$ g++ a.cpp b.cpp –save-temps -Wall
u@macbook c++$
declaration VS. definition
在C++中,
1.一个.CPP文件就是一个编译单元,
2.只有declaration声明允许被放在.H文件中
包括extern变量、函数原型、类/结构体声明
关于#include
作用:在需要的地方插入include的内容
1.#include “xx.h”,现在当前目录寻找,然后指定指定目录
2.#include <xx.h>,在指定目录搜索
标准头文件
#ifndef _MY_H_
#define _MY_H_
#endif / _MY_H_ /
我们修改a.h如下:
C:\Users\u\Desktop\a>ty
#define _MY_H_
#ifndef _MY_H_
#define _MY_H_
void f();
extern int global;
#endif //define _MY_H_
#define _MY_H_
#ifndef _MY_H_
#define _MY_H_
void f();
extern int global;
#endif //define _MY_H_
重新编译,不链接,如下:
C:\Users\u\Desktop\a>g++ a.cpp –save-temps -c
C:\Users\u\Desktop\a>type a.ii
# 1 "a.cpp"
# 1 "<command-line>"
# 1 "a.cpp"
# 1 "a.h" 1
# 2 "a.cpp" 2
int main(){
return 0;
}
C:\Users\u\Desktop\a>type a.ii
# 1 "a.cpp"
# 1 "<command-line>"
# 1 "a.cpp"
# 1 "a.h" 1
# 2 "a.cpp" 2
int main(){
return 0;
}
可以看出来a.ii里面没有a.h的内容,好像没来过一样,其实是有痕迹的,这样做比较极端,我们再改一下a.h如下
C:\Users\u\Desktop\a>type a.h
#ifndef _MY_H_
#define _MY_H_
void f();
extern int global;
#endif //define _MY_H_
#ifndef _MY_H_
#define _MY_H_
void f();
extern int global;
#endif //define _MY_H_
重新编译可以看出来,是有a.h的内容的
C:\Users\u\Desktop\a>g++ a.cpp –save-temps -c
C:\Users\u\Desktop\a>type a.ii
# 1 "a.cpp"
# 1 "<command-line>"
# 1 "a.cpp"
# 1 "a.h" 1
void f();
extern int global;
# 2 "a.cpp" 2
int main(){
return 0;
}
C:\Users\u\Desktop\a>type a.ii
# 1 "a.cpp"
# 1 "<command-line>"
# 1 "a.cpp"
# 1 "a.h" 1
void f();
extern int global;
# 2 "a.cpp" 2
int main(){
return 0;
}
接下来我们改一下a.cpp,成这样子
C:\Users\u\Desktop\a>type a.cpp
#define _MY_H_
#include "a.h"
int main(){
return 0;
}
#define _MY_H_
#include "a.h"
int main(){
return 0;
}
对于这个.cpp来说define的内容是存在的,因此条件编译就会把那几行给拿走,我们来试一下
C:\Users\u\Desktop\a>g++ a.cpp –save-temps -c
C:\Users\u\Desktop\a>type a.ii
# 1 "a.cpp"
# 1 "<command-line>"
# 1 "a.cpp"
# 1 "a.h" 1
# 4 "a.cpp" 2
int main(){
return 0;
}
C:\Users\u\Desktop\a>type a.ii
# 1 "a.cpp"
# 1 "<command-line>"
# 1 "a.cpp"
# 1 "a.h" 1
# 4 "a.cpp" 2
int main(){
return 0;
}
没有了吧,有a.h但是那两行(a.h的内容)没有了。我们还可以做一件事情让那两行不出现,我们把a.cpp中#defien的内容去掉,编译的时候这样编译:
C:\Users\u\Desktop\a>g++ a.cpp –save-temps -c -D_MY_H_
C:\Users\u\Desktop\a>type a.ii
# 1 "a.cpp"
# 1 "<command-line>"
# 1 "a.cpp"
# 1 "a.h" 1
# 2 "a.cpp" 2
int main(){
return 0;
}
C:\Users\u\Desktop\a>type a.ii
# 1 "a.cpp"
# 1 "<command-line>"
# 1 "a.cpp"
# 1 "a.h" 1
# 2 "a.cpp" 2
int main(){
return 0;
}
这种编译时告诉编译器所有的编译都带着_MY_H_这个宏,所以所有的选项中有这个条件就起作用。好,现在我们已经认识到宏条件编译起的什么作用。我们看这么一个例子,去掉宏,在a.h中添加个类 class A;添加个b.h在b.h中声明全局变量extern A a;
C:\Users\u\Desktop\a>type a.h
void f();
extern int global;
class A{};
C:\Users\u\Desktop\a>type b.h
#include "a.h"
extern A a;
void f();
extern int global;
class A{};
C:\Users\u\Desktop\a>type b.h
#include "a.h"
extern A a;
修改a.cpp如下:
C:\Users\u\Desktop\a>type a.cpp
#include "a.h"
#include "b.h"
int main(){
A a;
return 0;
}
#include "a.h"
#include "b.h"
int main(){
A a;
return 0;
}
C:\Users\u\Desktop\a>g++ a.cpp
In file included from b.h:1:0,
from a.cpp:2:
a.h:4:7: error: redefinition of ‘class A’
In file included from a.cpp:1:0:
a.h:4:7: error: previous definition of ‘class A’
C:\Users\u\Desktop\a>g++ a.cpp –save-temps
In file included from b.h:1:0,
from a.cpp:2:
a.h:4:7: error: redefinition of ‘class A’
In file included from a.cpp:1:0:
a.h:4:7: error: previous definition of ‘class A’
In file included from b.h:1:0,
from a.cpp:2:
a.h:4:7: error: redefinition of ‘class A’
In file included from a.cpp:1:0:
a.h:4:7: error: previous definition of ‘class A’
C:\Users\u\Desktop\a>g++ a.cpp –save-temps
In file included from b.h:1:0,
from a.cpp:2:
a.h:4:7: error: redefinition of ‘class A’
In file included from a.cpp:1:0:
a.h:4:7: error: previous definition of ‘class A’
C:\Users\u\Desktop\a>type a.ii
# 1 "a.cpp"
# 1 "<command-line>"
# 1 "a.cpp"
# 1 "a.h" 1
void f();
extern int global;
class A{};
# 2 "a.cpp" 2
# 1 "b.h" 1
# 1 "a.h" 1
void f();
extern int global;
class A{};
# 2 "b.h" 2
extern A a;
# 3 "a.cpp" 2
int main(){
A a;
return 0;
}
# 1 "a.cpp"
# 1 "<command-line>"
# 1 "a.cpp"
# 1 "a.h" 1
void f();
extern int global;
class A{};
# 2 "a.cpp" 2
# 1 "b.h" 1
# 1 "a.h" 1
void f();
extern int global;
class A{};
# 2 "b.h" 2
extern A a;
# 3 "a.cpp" 2
int main(){
A a;
return 0;
}
可以看到由于b.h include了a.h因此class A{};出现了两次,怎么解决这个问题呢
我们可以利用条件编译,如下
C:\Users\u\Desktop\a>type a.h
#ifndef _A_H_
#define _A_H_
void f();
extern int global;
class A{};
#endif
#ifndef _A_H_
#define _A_H_
void f();
extern int global;
class A{};
#endif
这样在第一次编译a.h的时候由于之前没有a.h所以a.h会被编译,当接下来编译b.h的时候,b.h include了a.h也就是说a.h第二次出现,这样条件编译就会起作用,由于第一次确实没有a.h,而第二次已经有了a.h,条件编译的时候会把a.h拿掉,再来测试一下:
C:\Users\u\Desktop\a>g++ a.cpp –save-temps
OK没问题
C:\Users\u\Desktop\a>type a.ii
# 1 "a.cpp"
# 1 "<command-line>"
# 1 "a.cpp"
# 1 "a.h" 1
void f();
extern int global;
class A{};
# 2 "a.cpp" 2
# 1 "b.h" 1
extern A a;
# 3 "a.cpp" 2
int main(){
A a;
return 0;
}
# 1 "a.cpp"
# 1 "<command-line>"
# 1 "a.cpp"
# 1 "a.h" 1
void f();
extern int global;
class A{};
# 2 "a.cpp" 2
# 1 "b.h" 1
extern A a;
# 3 "a.cpp" 2
int main(){
A a;
return 0;
}
因此 .
.H中放声明而不放定义,是为了避免有多个.CPP去 include同一个.H的时候,link遇见重复定义的东西
.H中使用标准头文件结构,是为了防止一个.CPP中include同一个.H多次的时候,出现那个.H中类class的声明被重复出现
这是解决两个不同问题的手段。
技巧:
1.一个头文件中只放一个类的声明(a.H);
2.它对应的源代码用相同的前缀(a.cpp);
3.头文件要用标准头文件围绕起来(#ifndef #define #endif)
So #include的内容只能是declaration,不能是definition,所以绝对不能include .CPP,因为.h中放的都是declaration,.CPP中是body放的都是definition,不能重复出现。
成员变量在哪里?他不在类里面,而是在类的每一个对象里面。
成员变量就是全局变量么?
不是的,成员变量的生命周期和这个对象的生命周期是一样的,全局变量的生命周期和程序的生命周期是一致的。两个的存储空间都不一样,全局变量的存储在静态存储区,成员变量存储在栈中。
比如说,跟Person是一个定义一样(就是一个class),你是一个具体的人(就是一个具体的实例),你可以说每个Person都有一个心脏。但是实际上心脏只能存在于具体的一个人的体内,而不是存在于Person这个定义里。
里面提到的成员变量i,对象a的i,和对象b中的i是否互相有影响?还是只是自己定义自己的i,可以不同值?