文章目录




1. 定义函数必须指定四个元素:返回类型、函数名、圆括号里面的形参(可能为空)和函数体(以花括号开始并以花括号结束的语句块)。

2. main函数的返回值是一个状态指示器,通常返回0,表示main函数成功执行完毕。

3. 大多数情况下学习语言之前要先学习IDE,其实从简单的命令行开始学习可能更容易些。

4. 源文件由文件名和文件后缀组成。



C++用命名空间来管理类,函数,以及其他的成员。

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_

重新编译,不链接,如下:

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;

}

可以看出来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_

重新编译可以看出来,是有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;

}

接下来我们改一下a.cpp,成这样子

C:\Users\u\Desktop\a>type a.cpp

#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;

}

没有了吧,有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;

}

这种编译时告诉编译器所有的编译都带着_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;

修改a.cpp如下:

C:\Users\u\Desktop\a>type a.cpp

#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’

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;

}

可以看到由于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

这样在第一次编译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;

}

因此 .

.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,可以不同值?




文章目录