104虚基类 在多重继承过程中,可能发生在最终的派生类中存在某一个基 类的多个副本的现象。比如,“大学生”类和“职工”类均可 以从“人”类派生出来,“职工大学生”又可以通过从“大学 生”类和“职工”类多重继承而来。但这个最终类中存在两个 “人”类的副本。如下图所示 Name PersonaGe Person Person uSex Student dEpartment sPeciality Student orker N ame Person UAge uSex Worker Work Stul dEpartment Job
10.4 虚基类 在多重继承过程中,可能发生在最终的派生类中存在某一个基 类的多个副本的现象。比如,“大学生”类和“职工”类均可 以从“人”类派生出来,“职工大学生”又可以通过从“大学 生”类和“职工”类多重继承而来。但这个最终类中存在两个 “人”类的副本。如下图所示。 Person Person Student Worker Work_Stu Person Person Student Worker pName uAge uSex pName uAge uSex pDepartment pDepartment pSpeciality pJob
从上图可见,类中存在某一基类的多个副本不仅浪费了存储 空间,而且导致二义性。更为严重的是为了保持多个副本中 数据成员值的同步,将使操作变得极为复杂 若欲保证派生类中仅有所有基类的一个副本,则应将其所有 基类说明为虚基类。说明虚基类的一般形式为: class derivative, virtual access base ∥ } 其中,关键字ua既可以放在访问控制字之前,也可以放 在访问控制字之后 个类无论是否存在虚基类,其对象的使用方式完全一样
从上图可见,类中存在某一基类的多个副本不仅浪费了存储 空间,而且导致二义性。更为严重的是为了保持多个副本中 数据成员值的同步,将使操作变得极为复杂。 若欲保证派生类中仅有所有基类的一个副本,则应将其所有 基类说明为虚基类。说明虚基类的一般形式为: class derivative : virtual base { //… }; 其中,关键字 virtual 既可以放在访问控制字之前,也可以放 在访问控制字之后。 一个类无论是否存在虚基类,其对象的使用方式完全一样
例如,可以用以下的形式定义类 Student、 Worker和Work_stu class Student: virtual public Person private char * dEpartment;∥系部 char *sPeciality; ∥专业 class Worker: virtual public Person i private char' dEpartment;/工作部门 char pOb 工种 ∥/
例如,可以用以下的形式定义类 Student、Worker 和 Work_stu: class Student : virtual public Person { private: char *pDepartment; // 系部 char *pSpeciality; // 专业 // … }; class Worker : virtual public Person { private: char *pDepartment; // 工作部门 char *pJob; // 工种 // … };
class Work Stu: public Student, public Work 这样,类 Work stu的派生关系就如下图所示(注意:该类的对 象中,数据成员 dEpartment存在二义性) pName Person uAge uSex Student Worker dEpartment sPeciality Work Stu Department pOb
class Work_Stu : public Student, public Work { // … }; 这样,类 Work_Stu 的派生关系就如下图所示(注意:该类的对 象中,数据成员 pDepartment 存在二义性)。 Person Student Work_Stu Worker pName uAge uSex pDepartment pDepartment pSpeciality pJob
第11章类的其它特性 11.1友元函数 1111友元函数的说明和定义 友元函数也叫友元,是在类中说明的、用关键字 friend修饰 的普通函数。友元虽然不是类中的成员函数,但却拥有访间类 中任何成员的特权。说明友元的一般形式为 friend type func_ name(arg_ list); 注意:友元的函数原型必须在类中说明,且不受访问权限的制 约。说明它的类授予它有访问类中所有成员的权利
第11章 类的其它特性 11.1 友元函数 11.1.1 友元函数的说明和定义 友元函数也叫友元,是在类中说明的、用关键字 friend 修饰 的普通函数。友元虽然不是类中的成员函数,但却拥有访问类 中任何成员的特权。说明友元的一般形式为: friend type func_name(arg_list); 注意:友元的函数原型必须在类中说明,且不受访问权限的制 约。说明它的类授予它有访问类中所有成员的权利
include class X private: int x friend long Power(X&, int) public (inta=0):x(a)各 void Set(int a)i X=a, 1 int Geto returnx; J ∥待续
#include class X { private: int x; friend long Power(X&, int); public: X(int a = 0) : x(a) {} void Set(int a) { x = a; } int Get() { return x; } }; // 待续
由于友元不是类中的成员函数而只是一个普通函数,所以习 惯上总是在类外定义,即使是内联函数也是如此。对于本例 而言,上述的“待续”由以下的内容替换: long Power(X& rx, int exp) long power= 1 while(exp >0) i 注意:由于友元 Power(0不是 类X的成员函数,所以this指 power=rX.X, 针与它无关。为了能够访问类 exp 中的成员,就只有利用参数将 X类的对象传给它以使其有访 return power; 问对象中成员的机会。 友元至少应当有一个说明它的 类类型的参数。 ∥待续
由于友元不是类中的成员函数而只是一个普通函数,所以习 惯上总是在类外定义,即使是内联函数也是如此。对于本例 而言,上述的“待续”由以下的内容替换: long Power(X& rx, int exp) { long power = 1; while(exp > 0) { power *= rx.x; exp --; } return power; } // 待续 注意:由于友元 Power() 不是 类 X 的成员函数,所以 this 指 针与它无关。为了能够访问类 中的成员,就只有利用参数将 X 类的对象传给它以使其有访 问对象中成员的机会。 友元至少应当有一个说明它的 类类型的参数
11.1.2使用友元函数 友元是一个普通函数,因此它与所有非成员函数的用法完全 样。例,用以下内容替换上述“待续” void maino x aX(5) cout < Power(ax, 3)<<endl; 从输出125
11.1.2 使用友元函数 友元是一个普通函数,因此它与所有非成员函数的用法完全 一样。例,用以下内容替换上述“待续”: void main() { X aX(5); cout << Power(aX, 3) << endl; // 输出 125 }
1113成员函数用作友元 从理论上讲,只要类给予授权,任何一个函数都可以成为友元。 自然,一个类中的成员函数可以作为另一个类的友元。例 class Y ∥超前说明 class X t public (inta=0):x(a)各} void Set(Y& ry) X=ryy Geto i return X
11.1.3 成员函数用作友元 从理论上讲,只要类给予授权,任何一个函数都可以成为友元。 自然,一个类中的成员函数可以作为另一个类的友元。例: class Y; // 超前说明 class X { int x; public: X(int a = 0) : x(a) {} void Set(Y& ry) { x = ry.y; } int Get() { return x; } };
class Y y public Y(inta=0):y(a)各} void Set(int a)i y=a; y int Get( return y; y friend voidⅩ∴Set(Y&); #include void maino Y aY(5); x aX. aX set(aY) cout < ax Geto << It'<< aY.Get( < endl
class Y { int y; public: Y(int a = 0) : y(a) {} void Set(int a) { y = a; } int Get() { return y; } friend void X :: Set(Y&); }; #include void main() { Y aY(5); X aX; aX.Set(aY); cout << aX.Get() << '\t' << aY.Get() << endl; }