20150516
头文件,以h为后缀名,包含函数,数据(包括数据类型定义),类等的声明。
在例子中多次引用“iostream”头文件,就是为了共享声明在其中的输入输出流对象
把子模块的声明放在头文件中,将具体的实现放在对应的源文件中
在一个程序的所有源代码中,源文件和头文件各司其职,共同完成一个完整的程序
源文件和头文件不仅在内容上有差别,在使用上也有很大的差别
不允许头文件引用源文件。虽然语法上可以。
头文件可以引用其他的头文件,构成新的头文件
头文件 stdafx.h就是多个头文件的集合
为了避免在一个程序中,一个头文件可能被多个源文件引用,为了防止头文件被多次编译,导致其中所声明的变量或者函数被重复多次声明。
解决办法:使用一些预编译指令来防止一个头文件被多次编译。
可以在头文件中加入 #pragma once,这个预编译指令可以防止一个头文件被多次编译。
名字空间:
使用名字空间(namespace)来规划和管理程序结构
把相同的名字放在不同的名字空间,这样就互不影响了
名字空间语法格式:
namespace 名字空间名
{
}
在名字空间中声明和定义的内容都属于这个名字空间
名字空间具有包装功能
namespace zhangsan
{
//名字空间zhangshan中的student数据结构
struct student
{
int nindex;
int nage;//年龄
};
};
namespace lisi
{
struct student
{
int nindex;
string strname;//姓名
};
};
//如果没有说明在哪一个具体的名字空间,则默认在全局名字空间
struct student //全局名字空间中student数据结构
{
int nindex;
bool bmale;//性别
};
当名字空间zhangsan和全局名字空间都有student的定义,使用默认的名字空间无法区分这个结构体,必须显示的使用域操作符“::"指明它所在的名字空间。
作用域
作用域分为局部作用域和全局作用域
作用域定义了某个标识符在程序中有效的区域。如果在某个作用域内标识符是有效的,可以引用,就说这个标识符在这个作用域内可见。
局部作用域
用{}大括号括起来的代码范围。如果局部作用域中包含更小的子作用域,则子作用域具有较高的优先级。
常见的局部作用域有函数体,如if,for,while,switch
最好不要在一个函数中定义两个同名的变量
下面这种情况最好不要出现
void foo(void)
{
int nnum=0;
{
int nnum;
nnum=1;
cout<<"在局部作用域中输出:“<<nnum<<endl;
}
cout<<"在函数体作用域中输出:"<<nnum<<endl;
}
如果变量或者函数不在任何局部作用域,就说这个变量或者函数在全局作用域中个,成为全部变量或者全局函数。
20150517
全局作用域就是整个源文件范围
int gn;
void globalfunc(int a ,int b)
{
for(gn=0;gn<0;++gn)//访问全局变量
{
//...
}
}
int _tmain(int argc,_tchar* argv[])
{
gn=3; //访问全局变量
globalfunc(2,4); //调用全局函数
return 0;
}
全局变量在源文件的任何位置都可以被调用
全局函数在源文件的任何位置都可以被调用
还可以在多个源文件中定义全局变量,主要是发生在一个程序由多个源文件和头文件组成的情况。
使用“extern”关键字可以找到定义在其他源文件中的全局变量
如果想使用某个变量或者函数,则必须事先进行声明。
//global.cpp :定义全局变量和全局函数
#include "stdafx.h"
int gtotal=0;
int add(int a ,int b)//这里是个函数取个大概的名字,下面会告诉我们这个函数具体会执行什么操作,像这个是,返回a+b的和,如果在别的地方引用这个函数的时候,直接引用add(int a,int b)就会达到返回a+b的和的效果。
{
return a+b;
}
使用"extern"关键字
//helloworld.cpp 使用全局变量和全局函数
//在变量声明前加上“extern”关键字,重新声明全局变量
extern int gtotal;
//在函数声明前加上“extern”关键字,重新声明全局函数
extern int add(int a,int b);
int _tmain(int argc,_tchar* argv[])
{
gtotal=add (2,3);
return 0;
}
编译预处理
在源代码中加入一下特殊的预编译指令来改变编译的过程,改变程序源代码结构和内容,达到灵活处理源文件的目的
最常用的预编译指令:
1、#include指令
这个指令更多是用来嵌入一个头文件,实现对声明在其中的变量或者函数的引用
语法格式为:
#include<文件名>
#include "文件名"
这两种格式的区别:
<>表示按照标准方式在编译器制定的目录下搜索这个文件,一般用来引入系统提供的头文件。
""表示先在当前目录下搜索,如果当前目录下没有这个文件,然后按照标准方式搜索。一般涌来引入自己创建的、放置在但钱项目文件夹下的头文件。
#include "stdafx.h"
#include<iostream>
#include "global.h"
2、#define #undef
一个是定义,一个是删除。
#define用来定义一个符号常量或者宏,一般这个定义的符号常量往往要在下面介绍的条件编译指令中使用到。
#undef作用是删除一个由#define定义的符号常量或者宏。
//定义一个符号常量 _debug
#define _debug
3、#if等条件编译指令
//如果定义了_debug标识符,就会编译中间的程序代码,为程序增加两个函数用于辅助调试。但像在编译release版本的时候,并没有定义_debug标识符,就不会编译这两个函数,从而减小程序体积。
#ifdef _debug
virtual void asservalid() const;
virtual void dump(cdumpcontext& dc) const;
#endif
4、#pragma once
用来制定当前文件在编译时只包含此次,避免同一个文件被多次引入而导致数目类型或者函数等的重复定义。
高手是怎样炼成的
用#define来定义一个宏
语法格式是:
#define 标识符 字符串
标识符就是符号常量,也称“宏名”
当定义好宏之后,就可以在程序代码中使用这个宏来代替定义中的字符串
#define PI 3.14159
double fR=5.0f;
double fArea=PI*fR*fR;
定义宏可以起到化繁为简的效果
带参数的宏定义的语法格式:
#define 标识符 (参数列表) 字符串
宏的参数没有类型的概念
使用有参数的宏进行宏展开时,不仅要对宏标识符作字符串替换,还必须作参数的替换。
//定义一个带参数的宏,取得两个数种比较大的一个数
#define max(a,b) ((a)>(b) ? (a):(b))
int nmax=max(2,4);
当进行宏展开时,这个宏寿险进行字符串的替换,这行代码变成:
int nmax=a>b ? a: b;
然后,使用宏的实际参数替换宏定义中的参数,这行代码最终成为:
int nmax=2>4 ? 2:4;
用typedef定义类型的别名
typed定义类型别名的语法格式为:
typedef 数据类型 数据类型别名
typedef int* PINT;
//定义一个PINT类型的变量,实际上就是iint*类型的变量
PINT pint=NULL;
1、定义一个类型的别名
效果:
typed int* PINT
PINT pint1,pint2
2、定义与平台无关的类型
typedef long double REAL;
当将代码移植到一个不支持long double 的平台时,可以把这个定义修改如下:
typedef double REAL;
3、为复杂的生命定义简单的别名
const
1、使用const代替#define定义常量
#define PI 3.1415926
const double PI =3.14159
第二种比第一种好
2、使用const表示常量
int const * pnumber
int * const pnumber=&number
两种区别,
一个const在*的左边,一个在*右边。在左边表示指针本身的值可变;在右边表示int变量值是可变的。
3、const用来表示函数的输入,输出参数
bool autoresizerect(crect& destrect,//输出参数可以修改
const crect& srcrect)//传入参数,不可修改
{
//...
}
没有const修饰的成员函数也称为变更函数
在声明类的成员函数时,如果在末尾加上const修饰,则表示在这个成员函数内不得改变改对象的任何数据。
class constdemo
{
public:
//在函数后添加const修饰,表示这是一个查看函数
char getvalueat(int nindex) const
{
//对类中的数据进行意外的修改,会导致一个编译错误
m_data[3]=‘A‘;
return m_data[nindex];
}