C++面向对象程序设计 第六章
好 我们继续下去,那联合union在C语言里面我们遇到过的,是吧,它和struct假如你要定义一个union
的话它和struct是不是很相似的?对不对,它也是像struct一样的,允许什么,就像结构一样 它允许啊
它的里面的多种元素呢是具有不同的数据类型, 是不是?但是呢它呢 和struct就是结构不一样的地方在
哪里呢?它的里面的这些成员数据啊都放在一个统一的内存当中,那么假如我们把一个联合定义在一个结构
或类的类型里面的话,比如像下面这样,本来我是定义一个结构struct这worker是工人的,那么它有自己的
数据成员.编号.姓名.级别.那么它本来还有一个职级,那本来这个职级的数据类型呢是union型,是不是?
struct worker //职工结构类型
{
char num[6] //编号
char name[12] //姓名
short kind; //类别
union //职级 没有起名字 无名联合
{
char cadre[7]; //干部职级
char teacher[12]; //教师职级
Short worker; //工人职级
};
};
struct worker employee; //
employee.cadre="kezhang" ;//
它是一个union的一个联合的一个名,那么在它的这个结构里面呢又有干部职级教师职级和工人职级.那么
你可以看到.它有没有给它起个名字啊?没有起名字,是不是?没有给这个union起名字,因此它就是一个无名
的联合,那么成为一个无名的联合在使用它的时候会怎么样呢?现在还是刚才那个结构,结构名呢就是worker
这个worker这个结构的定义,那么现在我在worker这个类型下面,我结构类类型下我定义了一个结构变量,
现在是真真实实有存储空间的变量,叫employee就是雇员, 对吧?啊我这里想想看,在这个worker前面加了
一个struct 我把它去掉行不行啊?可以的啊,就是前面讲过,在C++是可以的,在C是不可以的,是吧. 当我
通过employee这个结构变量啊来访问它的内部这个成员的时候,你看我通过employee访问这个number的话
应该怎么写啊?通过employee访问number的时候应该怎么写啊?你自己再自己再想想看,应该怎么写啊?
employee点,是不是?
对不对?对象打点number,是不是?唉,对.它是一个什么?整型的?是个什么东西啊? 是个字符型还是整型啊?给我
说一下是什么?是字符型的, 字符串六位的?你给我说一下我就不用换过去了吗. 啊是个字符串。那么它有
六位是不是000000。 有是吧?那么哦还不能这么来吧,字符还不能这样,这样来赋值.那么,怎么搞不下来啊,
但是当我访问它的这个在union这个下面的成员cadre的时候,本来我要通过union的这个什么变量,用
employee打点再union名字打点再cadre是不是?因为它是无名的话我就可以怎么样直接的使用,也就是它
前面所讲的,当你要访问它的数据成员的时候呢就把union的这个成员呢直接作为结构或类中的成员来使用,
那么对于这个无名的union这也是,它的这个数据成员i和f呢是放在同一个存储空间里面的,那么你要对它
进行存取的时候呢,也就是说你给它赋值,或者取它数值的时候呢 就直接叫出它的名字就可以了。为什么
呢?它前面没有名,对不对?有名的话你就把它名字写出来再点一下.是吧.是这样.
530
无名联合成员的使用
union
{
int i;
float f;
};
i=20;
f=3.5;
我们再来看强制类型转换,那么在C语言当中呢,如果要把一个整型的数据转换为浮点型的话呢,比如这个整型
的变量i,要转换为浮点型。因为要把它赋给什么浮点型的变量X的时候,我们把这个类型的名字啊写在这个
变量i的前面就好像是个运算符,对不对?就好像是个运算符呢对这个i变量进行什么?进行操作,把你这个i
后面加了个点名一样,是吧.那么在C++当中呢,它是让类型名呢像一个函数名一样.你看同样是变量整型变量i,
强制类型转换 在C语言中
int i=10;
float x=(float);
在C++语言当中
int i=10;
float x=float(i);
现在要换为浮点型.就让float象个什么? 像一个函数一样的,就用它把这个i就作为一个什么? 实参了。是不是?
然后返回的就是它的什么?它的返回值就是这个i转变为float型以后的那个数据。那么其实呢它这里使用的
方式呢是一致的,因为在下一堂课开始,我们将来就会讲到什么讲到类了class.那么如果呢你建立了一个
类, 比如它叫类名的话,那么这个类你可以在这个类名下面你当它是一种数据类型定义一个对象.你有的时候
啊也可以把这个类名呢作为一个什么?象作为一个函数一样的,把另外一个不同数据类型的变量转换成这个
类的一个什么?一个对象.因为你这个类名就是一个数据类型啊.把这个数据类型就像函数一样,
你,但是并不是真的作为函数, 但是就是看上去象作为一个什么函数一样的来使用的。
7:30
pchar=(char*)malloc(size of(char));
pint=(int*)malloc(size of(int));
pdouble=(double*)malloc(size of(double));
char *pchar;
int *pint;
double *pdouble;
pchar=new char;
pint=new int;
pdouble=new double;
然后我们我们来看NEW和delete,NEW和delete这两个运算符是做什么用场的呢?在C语言当中,也常常已经用到
过提供了这样的方便,就是说需要动态的分配和释放内存.什么叫动态的分配和释放内存呢?在C语言当中
当我们要用一个我们需要有一个数据啊要要要存放的时候我们习惯做的是什么呢?我们是说明一个变量,是不是?
然后呢就利用为系统为这个变量开的空间呢,我们就往这里面放东西存和取,那么如果是一大批数据的话,你
不知道这批数据有多大的话,你在做这件事情的时候,你就很可能开一个很大的数组,是不是?你就很可能开一个
很大的数组,但是你并不知道这个数组有多大你就尽可能给它开的很大,那么这样是的这样
是有可能保证什么保证你在运算过程当中 有足够的存储单元给你存放这些来来回回要变的数据.
那不好的地方是什么呢?如果在某次或者运行当中,其实我只是什么?少数的几个数据,但是我开的空间却什么非常大
是不是很浪费啊?对不对?那么就会想 能不能提供这样的一个功能,就是说我需要多少空间的时候你再动态的开给我.
我用完了以后呢再怎么?再还给你,然后需要的时候,再开,这样就好像比较节约了.对不对,我需要多大就开多大.
而不用事先定义一个很大的空间数组了.
9:20
struct node
{
char *string;
int value;
}
node *pnode
pnode=new node;
pnode->value=1;
delete pchar;
delete pint;
delete pdouble;
那么就是在这样的需求上呢,就有这样两个函数一个叫malloc就是分配内存 free 就是释放这内存这两个
函数.它就可以为我们动态的,什么叫动态的呢?就是在程序当中你根据需要来开它的大小,对吧,存储空间的
大小 你用完了还可以释放还给系统释放这内存,但是在C语言当中你使用这两个函数的时候呢,它就给你啊
定义了蛮细的规则,你看它是这样的当你用malloc这个函数来分配存储空间大小的时候
在它的这个实参里你必须告诉它是多大,是不是?是多大,你看,就是 char的size 这个sizeof char其实
其实sizeof 什么它本身就是一个函数,这个函数就是用来计算某种数据类型它所要占用的存储空间的大小是
几个字节,是不是?sizeof 然后你把这个数据类型放进来,为什么需要这个函数呢 这是因为C语言呢是可以在
不同种机型的机器上使用,而在不同的机器上微型计算机啊,那时候386和486啊,或者小型计算机啊.它们对
数据类型给分配的存储空间大小是什么是不一样的,有的是两个字节有的是四个字节,是不是?唉,就是为了
对付这种不同的机型,但是呢我这个函数唉我的这个语言呢可以在这种不同的机器上编程需要的话,
那么因此呢 它就有一个sizeof这样的函数,给你当场的来怎么来算一算,在你这台机器上这种数据类型要
占多少字节,是吧.它算出来因此sizeof它的返回值就是这个什么,数据类型的字节数的大小多少,是一个字节两个字节
还是四个字节.那么这个malloc就知道到底开多大了. 是不是 ,开完了这个空间以后就把它的首地址赋给了什么,要赋给
一个指针,这个指针的名字叫PZhi char 是不是 赋给指针 它还不能直接赋给指针呢 它还得把这个地址转换成
是什么?指向char型的指针,唉 它还得转换.这说明malloc这个函数啊它可以为各种各样的数据类型分配各
种各样的空间.但是它返回的指针类型是不一样的 什么道理呢?因为不同的数据类型呢它所占用的字节数是不一样的
是不是?那么当它的指针数加一或者减一的时候 它移动的字节数是不是不一样啊?对不对?因此 你返回给人家的那个地址 1212
应该是每移动一次是移动两个字节的还是四个字节的你得告诉别人,是不是?那么因此它返回的地址还的转换成
什么转换成当前机器上你那个char型的指针,明白没有 我告诉你你假如你是char型是占一个字节的,那么
我现在还给你的这个地址就告诉你,假如这个指针是增加一是移动一个字节的,假如你是二个字节的你就是移动二个字节
好那么我们可以看到这个malloc这个函数啊 它虽然提供给我们动态的分配内存的这样的功能,但是在用的时候有两点
第一要算一算数据类型的什么大小,第二返回的地址还得进行这就是刚才讲的叫强制类型转换,是不是?转换成char型的指针,
那么第二条你就可以看到它要把它转换成什么int型的指针,是不是,那么当然pchar 和pint这两个指针事先已经说明好了
它们分别是指向char型的和指向什么int型的,对吧
那么第三种呢 那么就是针对double的数据类型进行分配的.14
好那么我们可以知道free是干嘛用的呢? free这个函数那么它就是怎么释放这个指针所指向的那个空间,那么释放多少呢?
就是因为这里已经强制类型转换赋给了它就知道应该释放几个字节了, 对不对?那么在C++当中呢它提供了new和delete这两个运算符,
其实它们的功能就分别对应的new就是对应的什么? 内存分配malloc.delete呢就对应的free这个函数,它是来动态的分配和
删除这个存储块,但是当你用new算子的时候呢,是也要指明数据类型,可是呢你就不用怎么样啊?不用再来算一下这个数据类型啊1422
所占的大小了,而且呢new这个运算符它分配了这个存储块以后呢它也是返回它也是返回一个地址,是不是它返回这个地址的时候
也用不着进行这个前面的什么强制类型转换, 说我把它非得转换成是char型的还是int型的还是double型的
为什么呢 因为它就是在分配的时候告诉它是个char型的它就已经会返回一个char型的指针了,对吧.告诉它是int型的
它就会返回一个跟当前机器上兼容的那个int型的那个指针地址. 因此new呢这个算子运算符它只能分配一个足以放下
你只要指明它是什么样的数据类型它就会分配一个这样的存储空间,然后呢它返回的就是这个存储空间的首地址.
我们看这个下面的这几行例子,比如我们说明了Pchar指针是指向char型的变量,Pint是指向int型变量的
地址,它将来就要放int型变量的地址,对吧.那么Pdouble呢是指向一个double数据类型的地址,
现在我用new来怎么样开一个空间,开多大啊只要指明这个char型字符类型就可以了然后它返回的这个地址就一定
是什么指向char型的就给了pchar,用一个int类型的存储空间返回给Pint型 然后再动态分配一个double类型数据类型
的存储空间返回给指向double型数据变量的地址指针.
那么我们看这里new和delete呢,用new运算符可以为用户定义的这个数据类型啊分配存储空间,我们前面讲的是用什么样
数据类型啊?是标准的数据类型,是吧.int啊 float啊 double,那么你如果用户定义了struct定义了node结构变量.啊 1640
结构类型名叫node型,那么这个node这个数据类型它占的空间就是什么?有一个指向字符串指针的对不对?一个字符串指针
变量的这个存储空间,还有一个什么整型的变量value的存储空间,是不是? 那么这个node这个结构这种结构数据类型它包含的
存储空间要能什么?要能将来放下它这两个数据成员,是不是?一个是指针型的哦一个是char型的指针 一个是int型的变量
那么下面呢我们就可以在node这个数据类型下说明一个指针Pnode 对不对这个指针 然后呢我们用new开一个空间
这次开的空间是要多大啊?这个数据类型不是系统定义的标准数据类型是什么是我们用户什么自己定义的一个数据类型,
对不对?那么它就可以根据你这个node这个结构名呢 你在在定义的时候你说明了它这些数据成员的大小你就开一个什么
相应的空间,那么返回的这个地址呢就给了Pnode这样的一个指针.
那么我们把动态分配一个空间以后啊 这个空间它的大小就是将来就是node这个数据类型下
任何结构变量可以放的大小.是不是? 但是这个结构变量有没有名字啊?没有名字是不是?结构变量没有名字
当我们要访问它的数据成员它的里面的数据成员的时候我们怎么访问啊,因为我们把这个空间的首地址已经给了谁啊?19
给了这个指针,将来我再要访问这个动态开出来的空间的这些数据成员的时候,我就通过什么,通过这个指针指向来访问了
是不是?指针指向这个新的这个空间这个数据成员value给它赋值时的值.
那么用new这个运算符分配的这个存储块或者说这个动态分配的变量我们用完了不想要了我们就可以把它什么还给系统
还给系统的时候 那么怎么用法呢 我们用delete 把它的指针名叫出来 然后分号
比使用malloc和free有更多的方便了
那么用这样的形式呢就可以删除呢这个指针指向的存储块 那么有多少可以把它还给系统.
多少大小要还给系统呢?
那么当初你定义的时候就已经指明了他的大小是不是所以它释放的时候呢也不会多还也不会什么也不会少还 它就会做得正正好
那么在这里我们可以看到,用new 和delete
因为我告诉它 还有一个什么 数据成员
那个地址 就会分配一个这样的存储空间 int型变量的地址 用new开一个空间 它要开多大啊 node这个结构名啊 在double 地址
指针,那么我们看这里 我们前面讲的是用什么数据类型啊 那么这个 占的空间就是什么指向 字符串指针占的
空间,还有一个整型的这种数据类型 一个是指针型的说明一个是char型指针 一个是int型的变量
这次开的空间 那么 它就可以根据这个 说明这个成员的 任何结构变量可以
返回的 这样的一个指针 那么 我们把 大小是我们用户自己定义的一个数据结构类型 在定义的时候 那么返回的地址呢
这个空间放的地址 通过什么 通过指针指向 那么 就可以把它什么
所以释放的时候呢 所以释放的时候呢也不会多还也不会少还
就有 方便了 数据大小的计算和强制类型的转换 都不需要了 看一下214这个例子 这个例子很简单 那么delete
大家还记得吗 动态分配存储区目的是什么 也有点不合算 是不是已经占用了一个内存区了?
void funex(int code)
{
double A=0.6;
if(code==1)
{
int A=5;
::a=10;
cout<<A<<endl;
cout<<::A<<endl;
}
cout<<A<<endl;
}
void main()
{
funex(1);
cout<<A<<endl;
}

函数也可以使用sonst定义
空间里面发生改变得时候
这就是书上所说的 实参与这个形参匹配的时候,给它赋初值的时候
那么你所有的函数的外面呢 定义编译器就会发生错误就会指出来
那么就编的比较好,语言保持一种好的风格。
19
那么sonst所定义的这个常量呢既可以是局部的也可以呢是全局的,还记得变量局部和全局什么意思吗?
如果你是在一个一个块里面,就是一对大括弧组成的块里面或者说一个函数里面定义了这个
常量,它就是局部的,那么你在所有函数的外面外部定义了一个变量呢那个常量呢,它的生命期就是
全局的,一直到程序运行完毕。
那么在const的使用过程当中呢容易呢搞不明白出错误的地方呢就在这里啊,
它有三种,就是说这个const看你加在哪里,他的效果呀它是不一样的。
一种呢是叫做指向常量的指针,也就是说这个指针呢,啊它指到一个空间这个空间里面放的数据呢
是常量.然后呢你再也不能动它了,这叫指向常量的指针.
还有一种呢是叫做常量指针,也就是说这个指针里面的内容指针本身的内容也就是说这个地址啊
被作为常量了再也不能变,也就是说指针还能不能指向其他变量啊?或者常量啊?都不能指向。
指针只能指向那个存储空间,叫常量指针。
那么第三种呢也就是把前面两种结合起来,既指向常量,它自己也是什么?常数常量的指针.
我们看一看,第一种叫做指向常量的指针,这时候说明是怎么样的呢?
本来我说明一个指针name它是一个指针,因为它前面有一个星号, 是不是?它是指向一个字符,
那么一般它是指向一个字符串.
现在我在它前面再加一个const
这时候我在它前面呢 它本身还是一个指针变量
指针,它可以指向这个空间,它还可以指向什么其他空间,
它这个指针里面的内容是可以变的.也就是说它指针里面的内容是可以变的,
它可以指向这个空间,也可以指向那个存储空间,但是你在这里赋初值之后
这个例子就是我前面所讲的,就是求那个字符串长度的那个形参
是把什么 就不能变了 是把什么
那么函数体里面你有任何语句想要改变的话 就出错了。你看你看现在name这个指针 代表的是
首地址 第几个字符啊
第三个字符 是不是也 它就出错 但是字符一是不是也出错啊 它根本就不允许你做这个动作 也就是说
可不可以啊 可以的 指针是一个变量 拿到了什么
另外一个首赋初值,赋初值还是能改变的 这个数据类型的前面 是这样的啊,
对不对?还是将来指向的对象
const放在哪里啊 放在前面
字符串那个长度的函数 指针指向一个字符串的首地址
它等于什么 它现在已经是一个常量了指针所指向的name 加加的话就报错了
我下一次再调用它的时候 首地址给了这个Ps 它都可以变的 它的地址是可以变的
地址不能变了 是不是现在const把name先要在这里面放数据,然后就把这个首地址
它就不能再变了 固定的地方他就再也不能变了,地址被凝固了,再也不能变了.
好 因为它有这样的特点呢 另外一个字符串常量 下面呢我们来看 内置函数28
更多推荐


所有评论(0)