第五章 特殊函数和成员

第五章 特殊函数和成员

5.1 对象成员的初始化

可以在一个类中说明具有某个类的类型的数据成员,这些成员成为对象成员。在类A中说明对象成员的一般形式如下:

class A 

{

类名1 成员名1;

类名2 成员名2;

……

类名 成员名n;

};

说明对象成员是在类名之后给出对象成员的名字。为初始化对象成员,A类的构造函数要调用这些对象成员所在类的构造函数,A类的构造函数的定义形式如下:

A::A(参数表0):成员1(参数表1),成员2(参数表2),成员n(参数表n

{//其他操作}

冒号“:”后由逗号隔开的项目组成员初始化列表,其中的参数表给出了为调用相应成员所在类的构造函数时应提供的参数。参数列表中的参数都来自“参数表0”,可以使用任意复杂的表达式,其中可以有函数调用。如果初始化列表某项的参数表为空,则列表中相应的项可以省略。

对象成员构造函数的顺序取决于这些对象成员在类中说明的顺序,与他们在成员初始化列表中给出的顺序无关。析构函数的调用顺序与构造函数正好相反。

5.2 静态成员

简单成员函数是指声明中不含constvalatilestatic关键字的函数。如果类的数据成员或成员函数使用关键字static进行修饰,这样的成员称为静态数据成员或静态成员函数,统称为静态成员。

静态数据成员只能说明一次,如果在类中仅对静态数据成员进行声明,则必须在文件作用域的某个地方进行定义。在进行初始化之前,必须进行成员名限定。

注意:由于static不是函数中的一部分,所以在类声明之外定义静态成员函数时,不使用static。在类中定义的静态成员函数是内联的。

类中的任何成员函数都可以访问静态成员。因为静态成员函数没有this指针,所以静态成员函数只能通过对象名(或指向对象的指针)访问该对象的非静态成员。

静态成员函数与一般函数有如下不同:

(1)可以不指向某个具体的对象,只与类名连用。

(2)在没有建立对象之前,静态成员就已经存在。

(3)静态成员是类的成员,不是对象的成员。

(4)静态成员为该类的所有对象共享,它们被存储于一个公用的内存中。

(5)没有this指针,所以除非显式地把指针传给它们,否则不能存取类的数据成员。

(6)静态成员函数不能说明为虚函数。

(7)静态成员函数不能直接访问非静态函数。

静态对象具有如下性质:

(1)构造函数在代码执行过程中,第一次遇到它的时候变量定义时被调用,但直到整个程序结束之前仅调用一次。

(2)析构函数在整个程序退出之前被调用,同样也只调用一次。

5.3 友元函数

有时两个概念上相近的类要求其中一个类可以无限制地存取另一个类的成员。

友元函数解决了这类难题。友元函数可以存取私有成员、公有成员和保护成员。其实,友元函数可以是一个类或函数,尚未定义的类也可以作为友元引用。

1.类本身的友元函数

为本类声明一个友元函数,这时,虽然在类中说明它,但它并不是类的成员函数,所以可以在类外面像普通函数那样定义这个函数。

虽然友元函数是在类中说明的,但函数的定义一般在类之外,作用域的开始点在它的说明点,结束点和类的作用域相同。

友元说明可以出现于类的私有或公有部分。因为友元说明也必须出现于类中,所以应将友元看作类的接口的一部分。使用它的主要目的是提高程序效率。友元函数可以直接访问类对象的私有程序,因而省去调用类成员函数的开销。它的另一个优点是:类的设计者不必在考虑号该类的各种可能使用情况之后再设计这个类,而可以根据需要,通过使用友元增加类的接口。但使用友元的主要问题是:它允许友元函数访问对象的私有成员,这破坏了封装和数据隐藏,导致程序的可维护性变差,因此在使用友元时必须权衡得失。

注意:友元函数可以在类中声明时定义。如果在类外定义,不能再使用friend关键字。

2.将成员函数用作友元

一个类的成员函数(包括构造函数和析构函数)可以通过使用friend说明为另一个类的友元。

3.将一个类说明为另一个类的友元

可以将一个类说明为另一个类的友元。这时,整个类的成员函数均具有友元函数的性能。声明友元关系简化为“friend class 类名;”

需要注意的是,友元关系是不传递的,即当说明类A是类B的友元,类B又是类C的友元时,类A却不是类C的友元。这种友元关系也不具有交换性,即当说明类A是类B的友元时,类B不一定是类A的友元。

当一个类要和另一个类协同工作时,使一个类称为另一个类的友元是很有用的。

友元声明与访问控制无关。友元声明在私有区域进行或在公有区域进行是没有太大区别的。虽然友元函数的声明可以置于任何部分,但通常置于能强调其功能的地方以使其直观。对友元函数声明的惟一限制是该函数必须出现在类声明内的某一部分。

5.4 const对象

可以在类中使用const关键字定义数据成员和成员函数或修饰一个对象。一个const对象只能访问const成员函数,否则将产生编译错误。

1.常量成员

常量成员包括常量数据成员、静态常数据成员和常引用。静态常数据成员仍保留静态成员特征,需要在类外初始化。常数据成员和常引用只能通过初始化列表来获得初值。

2.常引用作为函数参数

使用引用作为参数,传送的是地址。但有时仅希望将参数的值提供给函数使用,并不允许函数改变对象的值,这时可以使用常引用作为参数。

3.常对象

在对象名前使用const声明常量对象,但声明时必须同时进行初始化,而且不能被更新。定义的语法如下:

类名 const 对象名(参数表);

4.常成员函数

可以声明一个成员函数为const函数。一个const对象可以调用const函数,但不能调用非const成员函数。const放在函数声明之前意味着返回值是常量,但这不符合语法。必须将关键字const放在参数列表之后,才能说明该函数是一个const成员函数。声明常成员函数的格式如下:

类型标识符 函数名(参数列表) const;

为了保证不仅声明const成员函数,而且确实也定义为const函数,程序员在定义函数时必须重申const声明。也就是说,const已经成为这种成员函数识别符的一部分,编译器和连接程序都要检查const。定义格式如下:

类型标识符 类名::函数名(参数列表)const{//函数体}

const位于函数参数表之后,函数体之前。也可以在类中用内联函数定义const函数。

类型标识符 函数名(参数列表)const{//函数体}

在定义成员函数时,函数体之前加上const可以防止覆盖函数改变数据成员的值。

在常成员函数里,不能更新对象的数据成员,也不能调用该类中没有用const修饰的成员函数。如果将一个对象说明为常对象,则通过该对象只能调用它的const成员函数,不能调用其他成员函数。

注意:用const声明static成员函数没有什么作用。在C++中声明构造函数和析构函数时使用const关键字均是非法的,但有些C++的编译程序并不给出出错信息。volatile关键字的使用方法与const类似,但因其很少用,此处不介绍。

5.5 数组和类

编译器调用适当的构造函数建立数组的每一个分量。如果找不到合适的构造函数,则产生错误信息。

5.6 指向类成员函数的指针

对象是一个完整的实体。为了支持这一封装,C++包含了指向类成员的指针。可以用普通指针访问内存中给定类型的任何对象,指向类成员的指针则用来访问某个特定类的对象中给定类型的任何成员。

C++既包含指向类数据成员函数的指针,又包含指向成员函数的指针。他提供一种特殊的指针类型,指针指向类的成员,而不是指向该类的一个对象中该成员的一个实例,这种指针称为指向类成员的指针。不过,指向类数据成员的指针要求数据成员是公有的,用途不大,所以不予介绍,仅简单介绍指向类成员函数的指针。

类并不是对象,但有时可将其视为对象来使用。可以声明并使用指向对象成员函数的指针。指向对象的指针是比较传统的指针,假设类A的成员函数为“void fa(void);”,如要建立一个指针pafn,它可以指向任何无参数和无返回值的类A的成员函数:

void(A::* pafn(void)

虽然“::”是作用域分辨符,但在这种情况下,“A::”最好读成“A的成员函数”,这时,从内往外看,此声明可读作:pafn是一个指针,指向类A的成员函数,此成员函数既无参数,也无返回值。下面的例子说明了pafn如何被赋值并用以调用函数fa

pafn=A::fa; //指向类A的成员函数fa的指针pafn

a x; //类A的对象x

A *px=&x; //指向类A对象x的指针px

(x.*pafn)(); //调用类A的对象x的成员函数fa

(px->pafn)(); //调用类A的对象x的指针px指向的成员函数fa

指向类A中参数类型列表为list,返回类型为type的成员函数的指针声明形式如下:

type(A::* pointer)(list);

如果类A的成员函数fun的原型与pointer所指向的函数的原型一样,则语句

pointer=A::fun;

将该函数的地址(这个地址不是真实地址,而是在A类中所有对象的便宜)置给了pointer。在使用指向类成员函数的指针访问对象的某个成员函数时,必须指定一个对象。用对象名或引用调用pointer所指向的函数时,使用运算符“.*”,使用指向对象的指针调用pointer所指向的成员函数时,使用运算符“->*”。

5.7 求解一元二次方程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值