您的位置:首页 > 编程语言 > C语言/C++

谭浩强C++笔记(11-12章)

2016-03-03 11:17 190 查看
谭浩强C++笔记(11-12章)

第十一章 继承和派生类

抽象类与保护的成员函数:抽象类只能用作被继承,不能定义对象。含有纯虚函数和构造函数或析构函数不为public的类为抽象类。

当把类中的构造函数或析构函数说明为私有的时,所定义的类通常是没有任何实用意义的,不能用它来产生对象,不能用产生派生类。

多继承构造函数只和继承函数顺序相关(若有virtual继承,virtual优先),当有new和delete时,析构函数顺序不一定和构造函数相反。

利用类作用域符::来指明数据或函数的来源,只限于这个函数只有一份拷贝情况,若是virtual继承,孙类中也可以这样访问。在子类中也可以通过::来访问父类中函数或成员。

赋值兼容问题:子给父可以赋值,父不能给子赋值,赋值方式有指针、引用、对象直接赋值。

虚继承:当对一个类虚继承时,在子孙类中只有一份此类拷贝,可以在各类中通过::引用成员变量和函数。在子孙类中,直接用此类构造函数,若在子孙类中没有给其赋值,直接调用它自己的缺省值。

第十二章 类的其它特性

1.友元函数:友元函数放到类公有私有或保护区域无所谓,一个函数可以是好几个类的友元函数,函数实现可以在类中或类外。一般用友元函数取类中成员,而不修改类中成员,作用域与普通函数相同。当一个类中函数是另一个类友元函数时,注意友元函数实现在两个类定义后,且要加::来指明函数属于哪个类,当函数数实现中有new时,函数要参数要使用引用。

2.友元类:一个类可以是另一个类友元类,当子是父友元时,直接访问父中私有成员。

3.虚函数:函数前加virtual,则为虚函数,可以实现多态,主要用在父类子类指针指向中,实现多态。函数是虚函数时,在其继承类中也仍为虚函数(加virtual无所谓)。此时也可以用::访问具体一个类中此函数。

4. 关于虚函数,说明以下几点:虚函数不能是友元函数或静态成员函数,析构函数可以为虚函数,构造函数不能为虚函数,虚函数会加长程序执行时间。

5.虚函数访问:指向具体类实现部分。

6.纯虚函数:无函数实现体,不能定义对象,可以定义指针。若类2基于类1,类3基于类2,不能写成是类3基于类1和类2.

7.class base,A、B是基于base,C基于A和B。则让A和B基base时class B:virtual public base,就可以将C对象指针赋给base指针了。但是要注意,A和B中不能对同一函数实现,不然base指针指向函数时不知道是指向A中函数还是B中函数(C实现的除外)。

8. 静态成员和函数:静态成员要在类外部定义其值,只能定义一次值。可以直接用类名字::来访问它。静态函数只能用静态成员。几个类共用一块静态成员空间,不包含对象地址的this指针,不能把静态成员函数定义为虚函数,可将静态成员函数定义为内联的(inline)。

9.const、volatile对象和成员函数:用const修饰的对象,只能访问该类中用const修饰的成员函数,而其它的成员函数是不能访问的。用volatile修饰的对象,只能访问该类中用volatile修饰的成员函数,不能访问其它的成员函数。当希望成员函数只能引用成员数据的值,而不允许成员函数修改数据成员的值时,可用关键词const修饰成员函数。一旦在用const修饰的成员函数中出现修改成员数据的值时,将导致编译错误。

10. const成员函数则是指将const放在参数表之后,函数体之前,其一般格式为:<type> FuncName(<args>) const;其语义是指明这函数的this指针所指向的对象是一个常量,即规定了const成员函数不能修改对象的数据成员,在函数体内只能调用const成员函数,不能调用其它的成员函数。

用volatile修饰一个成员函数时,其一般格式为:<type> FuncName(<args>) volatile;其语义是指明成员函数具有一个易变的this指针,调用这个函数时,编译程序把属于此类的所有的数据成员都看作是易变的变量,编译器不要对这函数作优化工作。 由于关键字const和volatile是属于数据类型的组成部分,因此,若在类定义之外定义const成员函数或volatile成员函数时,则必须用这二个关键字修饰,否则编译器认为是重载函数,而不是定义const成员函数或volatile成员函数。

11. 指向类成员的指针:在C++中可以定义一种特殊的指针,它指向类中的成员函数或类中的数据成员。并可通过这样的指针来使用类中的数据成员或调用类中的成员函数。 指向类中数据成员的指针变量定义一个指向类中数据成员的指针变量的一般格式为:

<type> ClassName:: *PointName;其中type是指针PointName所指向数据的类型,它必须是类ClassName中某一数据成员的类型。

12:1、指向类中数据成员的指针变量不是类中的成员,这种指针变量应在类外定义。

2、与指向类中数据成员的指针变量同类型的任一数据成员,可将其地址赋给这种指针变量,赋值的一般格式为:

PointName = &ClassName::member;

这种赋值,是取该成员相对于该类的所在对象中的偏移量,即相对地址(距离开始位置的字节数)

如:mptr = &S::y; 表示将数据成员y的相对起始地址赋给指针变量mptr。

3、用这种指针访问数据成员时,必须指明是使用那一个对象的数据成员。当与对象结合使用时,其用法为:

ObjectName.* PointName

4、由于这种指针变量并不是类的成员,所以使用它只能访问对象的公有数据成员。若要访问对象的私有数据成员,必须通过成员函数来实现。

举例如下:int A::*pz ;pz=&A::z;

13:指向类中成员函数的指针变量

定义一个指向类中成员函数的指针变量的一般格式为:

<type> (ClassName:: *PointName)(<ArgsList>);

其中PointName是指向类中成员函数的指针变量;ClassName是已定义的类名;type是通过函数指针PointName调用类中的成员函数时所返回值的数据类型,它必须与类ClassName中某一成员函数的返回值的类型相一致;<ArgsList>是函数的形式参数表。

在使用这种指向成员函数的指针前,应先对其赋值

PointName= ClassName::FuncName;

同样地,只是将指定成员函数的相对地址赋给指向成员函数的指针。

14:在调用时,用(对象名.指针)( )的形式。

比较 :int max( int a,int b)

{ return (a>b?a:b); }

若有:int (*f)( int, int ); f=max;

则调用时 (*f)(x,y);

所以:(s1.*mptr1)( ); (s1.*mptr2)(100);

或: (ps->*mptr1)( ); (ps-*mptr2)(100);

15:对指向成员函数的指针变量的使用方法说明以下几点:

1、指向类中成员函数的指针变量不是类中的成员,这种指针变量应在类外定义。

2、不能将任一成员函数的地址赋给指向成员函数的指针变量,只有成员函数的参数个数、参数类型、参数的顺序和函数的类型均与这种指针变量相同时,才能将成员函数的指针赋给这种变量。

3、使用这种指针变量来调用成员函数时,必须指明调用那一个对象的成员函数,这种指针变量是不能单独使用的。用对象名引用。

4、由于这种指针变量不是类的成员,所以用它只能调用公有的成员函数。若要访问类中的私有成员函数,必须通过类中的其它的公有成员函数。

5、当一个成员函数的指针指向一个虚函数,且通过指向对象的基类指针或对象的引用来访问该成员函数指针时,同样地产生运行时的多态性。

6、当用这种指针指向静态的成员函数时,可直接使用类名而不要列举对象名。这是由静态成员函数的特性所确定的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: