前面已经介绍了自定义类型的成员变量和成员函数的概念,并给出它们各自的语义,本文继续说明自定义类型剩下的内容,并说明各自的语义。 一、权限
成员函数的提供,使得自定义类型的语义从资源提升到了具有功能的资源。什么叫具有功能的资源?比如要把收音机映射为数字,需要映射的操作有调整收音机的频率以接收不同的电台;调整收音机的音量;打开和关闭收音机以防止电力的损耗。为此,收音机应映射为结构,类似下面:
struct Radiogram { double Frequency; /* 频率 */ void TurnFreq( double value ); // 改变频率 float Volume; /* 音量 */ void TurnVolume( float value ); // 改变音量 float Power; /* 电力 */ void TurnOnOff( bool bOn ); // 开关 bool bPowerOn; // 是否开启 };
上面的Radiogram::Frequency、Radiogram::Volume和Radiogram::Power由于定义为了结构Radiogram的成员,因此它们的语义分别为某收音机的频率、某收音机的音量和某收音机的电力。而其余的三个成员函数的语义也同样分别为改变某收音机的频率、改变某收音机的音量和打开或关闭某收音机的电源。注意这面的“某”,表示具体是哪个收音机的还不知道,只有通过成员操作符将左边的一个具体的收音机和它们结合时才知道是哪个收音机的,这也是为什么它们被称作偏移类型。这一点在下一篇将详细说明。
注意问题:为什么要将刚才的三个操作映射为结构Radiogram的成员函数?因为收音机具有这样的功能?那么对于选西瓜、切西瓜和吃西瓜,难道要定义一个结构,然后给它定义三个选、切、吃的成员函数??不是很荒谬吗?前者的三个操作是对结构的成员变量而言,而后者是对结构本身而言的。那么改成吃快餐,吃快餐的汉堡包、吃快餐的薯条和喝快餐的可乐。如果这里的两个吃和一个喝的操作变成了快餐的成员函数,表示是快餐的功能?!这其实是编程思想的问题,而这里其实就是所谓的面向对象编程思想,它虽然是很不错的思想,但并不一定是合适的,下篇将详细讨论。
上面我们之所以称收音机的换台是功能,是因为实际中我们自己是无法直接改变收音机的频率,必须通过旋转选台的那个旋钮来改变接收的频率,同样,调音量也是通过调节音量旋钮来实现的,而由于开机而导致的电力下降也不是我们直接导致,而是间接通过收听电台而导致的。因此上面的Radiogram::Power、Radiogram::Frequency等成员变量都具有一个特殊特性——外界,这台收音机以外的东西是无法改变它们的。为此,C++提供了一个语法来实现这种语义。在类型定义符中,给出这样的格式:<权限>:。这里的<权限>为public、protected和private中的一个,分别称作公共的、保护的和私有的,如下:
class Radiogram { protected: double m_Frequency; float m_Volume; float m_Power; private: bool m_bPowerOn; public: void TurnFreq( double ); void TurnVolume( float ); void TurnOnOff( bool ); };
可以发现,它和之前的标号的定义格式相同,但并不是语句修饰符,即可以struct ABC{ private: };。这里不用非要在private:后面接语句,因为它不是语句修饰符。从它开始,直到下一个这样的语法,之间所有的声明和定义而产生的成员变量或成员函数都带有了它所代表的语义。比如上面的类Radiogram,其中的Radiogram::m_Frequency、Radiogram::m_Volume和Radiogram::m_Power是保护的成员变量,Radiogram::m_bPowerOn是私有的成员变量,而剩下的三个成员函数都是公共的成员函数。注意上面的语法是可以重复的,如:struct ABC { public: public: long a; private: float b; public: char d; };。
什么意思?很简单,公共的成员外界可以访问,保护的成员外界不能访问,私有的成员外界及子类不能访问。关于子类后面说明。先看公共的。对于上面,如下将报错:
Radiogram a; a.m_Frequency = 23.0; a.m_Power = 1.0f; a.m_bPowerOn = true;
因为上面对a的三次操作都使用了a的保护或私有成员,编译器将报错,因为这两种成员外界是不能访问的。而a.TurnFreq( 10 );就没有任何问题,因为成员函数Radiogram::TurnFreq是公共成员,外界可以访问。那么什么叫外界?对于某个自定义类型,此自定义类型的成员函数的函数体内以外的一切能写代码的地方都称作外界。因此,对于上面的Radiogram,只有它的三个成员函数的函数体内可以访问它的成员变量。即下面的代码将没有问题。
void Radiogram::TurnFreq( double value ) { m_Frequency += value; }
因为m_Frequency被使用的地方是在Radiogram::TurnFreq的函数体内,不属于外界。
为什么要这样?表现最开始说的语义。首先,上面将成员定义成public或private对于最终生成的代码没有任何影响。然后,我之前说的调节接收频率是通过调节收音机里面的共谐电容的容量来实现的,这个电容的容量人必须借助元件才能做到,而将接收频率映射成数字后,由于是数字,则CPU就能修改。如果直接a.m_Frequency += 10;进行修改,就代码上的意义,其就为:执行这个方法的人将收音机的接收频率增加10KHz,这有违我们的客观世界,与前面的语义不合。因此将其作为语法的一种提供,由编译器来进行审查,可以让我们编写出更加符合我们所生活的世界的语义的代码。
应注意可以union ABC { long a; private: short b; };。这里的ABC::a之前没有任何修饰,那它是public还是protected?相信从前面举的那么多例子也已经看出,应该是public,这也是为什么我之前一直使用struct和union来定义自定义类型,否则之前的例子都将报错。而前篇说过结构和类只有一点很小的区别,那就是当成员没有进行修饰时,对于类,那个成员将是private而不是public,即如下将错误。
class ABC { long a; private: short b; }; ABC a; a.a = 13;
ABC::a由于前面的class而被看作private。就从这点,可以看出结构用于映射资源(可被直接使用的资源),而类用于映射具有功能的资源。下篇将详细讨论它们在语义上的差别。 <  
1/2 1 2 下一页 尾页 |