类的实践○六○:合理的使用
这一讲我们先接着上一讲来讲一讲条件编译,当然,我们不是讲全部的条件编译,我们讲这一讲我们使用得到的,那么什么叫条件编译呢?那就是当我们在不同的平台或不同的文件中,一个程序中的有些东西不同了,怎么办?
举个例子吧:我们暂时不说不同的机器啊,就是不同的平台,就是不同,我们C、C++中的字符串的结尾是以'\0'作为结尾的,我们称之为0串,或者Z串,那么在汇编语言中,字串的结尾标志则为'$',我们称之为$串,那么我们开发一个程序,如果是要对 Z串处理,很显然用下面的程序就一切OK:
for(...;ch[i]!='\0';...)
{
...
}
而如果我们在$串中呢?当然也可以这样做程序:
for(...;ch[i]!='$';...)
{
...
}
那么我们看这两个程序之间显然唯一不同的就是后面的那个结束符不同。
我们一句可以像这样地改,我们编写C程序处理Z串显然没什么问题,可如果我们的程序这样编写是不是更好?
#define STREND '\0'
for(...;ch[i]!=STREND;...)
{
...
}
我们显然知道,这种判断串尾的肯定在一个程序中不是一处,如果是多处,那么我们的程序就很方便了,如果要变成处理$串的程序就只需要改变一下定义宏:
#define STREND '$'
重新编译就一切OK了,有些人不重视宏的使用,其实不对的,我们做一个宏很容易实现一个程序的跨平台,跨系统,甚至运行在不同类型的计算机上,事实上就是如此。
于是,像上面定义宏一样,有好多的这样的处理指令,我们称之为预编译指令,专门处理这些事情的,举几个例子吧,或者是我们这一讲要用到的例子:
#if
#else
#elif
#endif
是不是大家觉得很面熟呢?在哪儿见过?其实就是这样的,但预编译指令不是指令,所以最后不要加分号这些指令都是给编译器看的,大家如果看过牛刀前面的《汇编实践》,大家一定知道在汇编中有“伪指令”这个词吧?其实意思差不多,我们以前学的C的指令都是编译成机器指令的,而预编译指令就是让机器知道我们的意图,从而在编译时有选择地编译,而不是将程序全编译了,说起来很冤,做一大气程序可能绝大多数没有用,谁让我们的计算机不是世界统一的呢?没办法。
上面的几个可能你一看就懂,下面的呢?
#ifdef
#ifndef
我们这一讲就着重讲这两个,其他还有好多的预处理,我们不教大家,至少暂时用不到:
大家知道为什么会有 #endif 吗?我们说过了,预处理的指令不是我们通常用的指令,所以没有语句行的概念,更没有语句块的概念,也就是说大括号不好使,那么这样一来,就必须有替代大括号作用的语句于是就有了 #endif 目的是用来结束上面的 #if 语句条件判断,这一点如果你是学VB过来的,那就好理解,容易理解了。
于是,我们举个例子,假如我们(我们说假如,可能系统并不是这样处理,而且肯定不是这样的,因为不是牛刀想当然的,呵呵)定义编译为 c++ 处理时,我们系统定义了一个宏 CPP 而处理 $串则定义了一个 ASM 宏,那么我们上面的程序就可以这样改动:
#ifdef CPP
#define STREND '\0'
#endif
#ifdef ASM
#define STREND '$'
#endif
这样一来,程序会根据我们前面是否定义了相应的宏而自动作出选择,也就是说,我们以后编译时,只需要在编译前,对相应的平台宏定义一下就一切OK了。
当然上面的条件编译其实是有问题的,如果系统对 CPP 与 ASM 都作了定义了,那么第一个宏定义与第二个宏定义就犯冲了,系统就会报错。但意思就是这个意思,有关宏与预编译的设计,相当麻烦,甚至有些代码你根本就不知道怎么回事,像前一讲我们讲的:
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
说实话,知道那么一点意思,但你不是系统程序员,就根本不知道这一句的功能。
行了,我们再来看看上一讲的遗留问题吧:
...
...
class A()
{
...
}
...
...
class A()
{
...
}
...
...
我们说过,类和函数是允许重载的,但并不是说真能同名,像上面这种同名,编译器显然要报错,那么这种程序我们在单文件的程序中显然不会做出这种类似的程序来,但在多文件的程序中,事实就不同了,一个巨大的程序可能分派给不同的部门,不同的程序员去完成,甚至是一个巨大的群体去完成,你知道人家文件中包含有哪些文件,有没有一个文件在不同的文件中多次被包含,显然是不可能做到不出任何问题的,于是,就必须用了我们这一讲的预编译指令了,我们给类前后加一些预编译的指令,大家看程序:
...
...
#ifndef CLASS_A
#define CLASS_A 12345
class A()
{
...
}
#endif
...
...
#ifndef CLASS_A
#define CLASS_A 12345
class A()
{
...
}
#endif
...
...
这样一来,有什么好处呢?大家看,当编译器第一次看到 #ifndef CLASS_A 时,是不是这样来,是不是没有定义 CLASS_A 呢?显然是,既然是,就进入了我们的预编译后的第一个类前面的那个 #define CLASS_A 12345 去执行了,是不?当然这一次一执行过了,这个宏就被定义了,并同时将 class A;这个类的定义包含了进来。
可当第二次遇到 #ifndef CLASS_A 时,已经被定义了啊,这个宏,所以第二个类的定义在预编译时,就被编译器自动不去处理了,当然后面不管包含多少次,这个类就只处理一次,这就是预编译指令的好处。
当然,这样一来,只要有了这两个预编译,不管我们一个类的文件被包含多少次,处理其实只处理一次,不就无形中实现了我们多文件类与函数的处理了吗?
显然这样一来,会有一个问题,假如我们这个类 CLASS_A 被我们在其他地方不小心定义了怎么办?这个类不就永远别想被包含进来了吗?于是,我们有了一些不成文的规则,大家都根据这个规则来做类,做其他的程序,一般就不会出现问题了:
规则:两个下划线+文件名+_H+两个下划线
其实这个规则牛刀没看有任何书,看有些人这样用过的,像上面 class A ,一般我们类的头文件名称为 a.h 那么定义时,就可以作如下定义:
#ifndef __A_H__
#define __A_H__
...
#endif
说实话,牛刀没见过任何书上说有这样一个规则啊,但一般我们定义宏不太可能用两个下划线开始去定义,所以如果大家都按这个规则,一般不会出问题。
但VC6.0做得就更绝了,大家看:
#if !defined(AFX_POINT_H__A70DC0BF_F0E6_4CFB_B110_CEF41DBE0C88__INCLUDED_)
#define AFX_POINT_H__A70DC0BF_F0E6_4CFB_B110_CEF41DBE0C88__INCLUDED_
...
#endif
大家看到 AFX_POINT_H__A70DC0BF_F0E6_4CFB_B110_CEF41DBE0C88__INCLUDED_ 了吧?你有本事做一个宏与之重名?当然这是系统自动生成的,所以我们接上面一讲,我们一般做一个类,都用系统做好的这一个工具,一般不会出问题,并且非常好用。
对了,给大家说一下啊,大家看
#define __A_H__
怎么没有定义宏的数值啊?其实这是一个空宏(“牛刀定义”,书上可能找不到),我们根本用不到这个数值,所以根本没必要定义数值,当然你定义一个一点关系都没有,但没有任何实际意义。这个宏的定义就是为了预处理,预编译,使得我们的程序编译后不会出现编译错误。仅此而已。
也就是说,一旦我们用系统的方法加进一个类,我们没有任何的后顾之忧。下面再看看,我们在VC6.0中,怎么对这个类进行操作。
怎么?类还有什么操作?原来VC6.0做得相当成熟,尤其对函数、类的操作,格外地方便,下面跟着牛刀,一步一步地来做:
任务一、给类定义一个变量:
大家打开“工作区”,在其中的 ClassView 选项卡上双击 Point 就可以看到右面给我们列出了如我们上一讲的定义部分,其实定义变量很简单,在类的定义中敲就一切OK了。
但牛刀与大家来个绝的,也是常用的:
右击Point类,弹出一个菜单,选择:Add Member Variable...
系统会弹出一个对话框:
大家看,挺好玩,我们可以在 Variable Type: 下面的文本框中输入 int 而在 Variable Name: 下面文本框中输入: x ,然后选择下面的 Private ,按“OK”
你瞧瞧,系统自动给我们增加了一个:
private:
int x;
算了吧牛刀,这不是脱裤放屁——多此一举吗?
还真别说,果然是多此一举,但有些人就在这上出了点问题,特别是在 MFC 中,有些人根本不敢去改系统的任何一个数据或者变量,弄得太小心了,MFC 书看多了可能有些人就不太敢编程了,事实真的会如此,所以牛刀和大家说,这个功能,建议大家不要用,还不如直接在类中输入:
int y;
你看,多方便?
但大家想过没有,你如果真在做一个很大的程序,又想加一个类的全局变量,你舍不得离开自己做程序的地方啊,于是想用了,还是会不由地右击一下,加个想要的变量里面去就一切OK了,用这个右键的好处就是,根本不需要去类中找地方插入代码,随时随地都可以添加任一变量,实话说,你如果是学习的话,果真是脱裤放屁,但你真的做一个大型的程序,你就会体会到用这些工具有多么的方便了。
大家可知道,我们对类的编程不是在同一个文件中进行的啊,一个是头文件,一个是类文件,如果我们想要加入一个变量就要打开一个文件你说烦不烦?当然这里空口说可能没有说服力,大家在做程序的过程中细细体会吧。
任务二、增加一个函数:
同样,右键类图标,按 Add Member Function...
也是弹出一个对话框:
大家看结构与上面几乎如出一撤:
在 Function Type: 下面输入 void
在 Function Declaration: 下面输入 print()
选择 Public 点 “OK”
这里面说一下,下面多了一个 Static 和 Virtual ,一个是定义为固定函数,一个是定义为虚函数,这些我们以后再说。
增加函数,我们一般不手工添加,为什么?这个工具方便啊,函数原型与函数调用一
没有合适的资源?快使用搜索试试~ 我知道了~
c++高级程序员总结的C++基础
共40个文件
txt:40个
需积分: 9 9 下载量 197 浏览量
2009-07-29
23:37:48
上传
评论
收藏 194KB RAR 举报
温馨提示
c++高级程序员总结的C++基础,很好很适用 编程提高到捷径
资源推荐
资源详情
资源评论
收起资源包目录
C++基础.rar (40个子文件)
牛刀小试C++基础
牛刀教学021:邻居与仓库.txt 7KB
牛刀教学015:我爱我的家.txt 7KB
[原创]牛刀基础教学001:语言与函数.txt 2KB
牛刀教学013:两种运算符.txt 3KB
牛刀教学019:共用大仓库.txt 6KB
[原创]牛刀基础教学006:我调我自己.txt 8KB
牛刀教学018:共用小厨房.txt 7KB
牛刀教学023:自己的类型.txt 6KB
牛刀教学012:找到你的家.txt 13KB
[原创]牛刀基础教学008:怪怪的运算.txt 7KB
[原创]牛刀基础教学007:语句与表达式.txt 16KB
[原创]牛刀基础教学003:函数与类型.txt 8KB
牛刀教学022:牛刀隐江湖.txt 2KB
[原创]牛刀基础教学004:条件的判断.txt 7KB
牛刀教学017:墙上小抽屉.txt 4KB
牛刀教学011:串串糖葫芦.txt 16KB
[原创]牛刀基础教学009:奇妙的旋转.txt 9KB
[原创]牛刀基础教学002:函数的秘密.txt 3KB
牛刀教学016:家有好邻居.txt 7KB
[原创]牛刀基础教学010:惊魂病毒夜.txt 9KB
指针实践○四八-○五二
049指针实践○四九:指针的使用.txt 9KB
051指针实践○五一:指针与数组.txt 12KB
052指针实践○五二:指针与函数.txt 12KB
050指针实践○五○:固定的指针.txt 11KB
048指针实践○四八:指针的表白.txt 9KB
类的实践○五八-○六四
063类的实践○六三:特殊的指针.txt 15KB
058类的实践○五八:类与结构体.txt 14KB
060类的实践○六○:合理的使用.txt 16KB
061类的实践○六一:奇妙的父子.txt 15KB
064类的实践○六四:特别的函数.txt 15KB
059类的实践○五九:相同的函数.txt 14KB
062类的实践○六二:假假的函数.txt 15KB
牛刀教学014:新型的输出.txt 8KB
牛刀教学020:新的与旧的.txt 10KB
结构体实践○五三-○五七
056结构实践○五六:结构与循环.txt 14KB
054结构实践○五四:漫游结构体.txt 15KB
055结构实践○五五:常用结构体.txt 14KB
057结构实践○五七:结构与消息.txt 16KB
053结构实践○五三:初识结构体.txt 11KB
[原创]牛刀基础教学005:程序的流程.txt 4KB
共 40 条
- 1
资源评论
aichijingyu
- 粉丝: 0
- 资源: 21
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功