22
第 12 第 第第第第第第 12.1 第第第第 ( 第第第第第第第第第第第第 ) 给给给给给给 给给给给 , 给给给给给给给给给给给给给给给给给给给 给给给 , 给给给给给给给给给给 . 12.1.2 第第第第第第第 ( 第第 ) 给 12-1: 给给 给给 x 给给给给 , 给给给给 给给 x 给给给给给给给 Cube( ), 给给 5 给给给 . class C { int x; public: C(int a) {x=a;} // 给 给给给 int GetX(){return x;} friend long Cube(C&); // 给给给给给给 Cube( ), 给给给给给给给给 };

第 12 章 类和其他特性

  • Upload
    lindsay

  • View
    76

  • Download
    7

Embed Size (px)

DESCRIPTION

第 12 章 类和其他特性. 12.1 友元函数 ( 将 普通函数说明为友元函数 ) 给类外函数赋一定的权利 , 让该类函数能够访问该类内的私有成员和保护成员 , 该类函数称为友元函数 . 12.1.2 友元函数的定义 ( 说明 ) 例 12-1: 定义一个求 x 立方的类 , 同时说明一个求 x 立方的友元函数 Cube( ), 且求 5 的立方 . class C { int x; public: C(int a) {x=a;} // 构造函数 int GetX(){return x;} - PowerPoint PPT Presentation

Citation preview

第 12 章 类和其他特性12.1 友元函数 ( 将普通函数说明为友元函数 ) 给类外函数赋一定的权利 , 让该类函数能够访问该类内的私有成员和保护成员 , 该类函数称为友元函数 .12.1.2 友元函数的定义 ( 说明 )例 12-1: 定义一个求 x 立方的类 , 同时说明一个求 x 立方的友元函数 Cube( ), 且求 5 的立方 .class C { int x; public: C(int a) {x=a;} // 构造函数 int GetX(){return x;} friend long Cube(C&); // 定义友元函数 Cube( ), 形参为对象且引用 };

long Cube(C &c) // 定义类外函数 , { return (c.x*c.x*c.x); // 类外函数能够访问类内的私有成员,它不是类内函数。 }#include "iostream.h"void main(){

C c(5);cout<<Cube(c)<<endl; // 类外函数能够访问类

内的私有成员}

C c(5);->C( )->5->x-> Cube(c)-> return (c.x*c.x*c.x)

用类 C 定义对象 c()-> 调用构造函数 c()-> 给私有成员 x 赋值 -> 调用友元函数 -> 求结果

说明 :1.类外函数与类内成员函数在定义时有什么不同 ?2.类外函数通过什么访问类内的成员 ?3.如果不直接使用类外函数求 X 的立方 ?4.为什么定义了 GetX( ) 而没有使用 ? ( 两种方

法 )5.类外函数可以使用 inline 说明为内联函数。6.为什么将对象说明成引用 ? Cube(C&) 。

12.1.2 友元函数(被说明成友元函数,它可以调用另一个类中的成员 )例 : 12-2#include "iostream.h"class Y; // 由于在定义类 Y 之前要使用 , 所以提前说明class X { private : int x; public: X(int a) {x=a;} int GetX( ) {return x;} void SetX(Y&);// 形参为 Y 类的对象,类外定义 };

class Y { private : int y; public: Y(int b=0) {y=b;} // 定义带参数构造函数 int GetY( ){return y;} friend void X::SetX(Y&); //A , SetX ( × )是

Y 的友元函数 }; void X::SetX(Y&r) // 函数定义, Setx ()是类 Y 友元函数 {

x=r.y; // 可以调用 Y 中的成员给类 X 成员赋值 }

void main() { X m(5); Y n(10); cout<<"X="<<m.GetX( )<<'\t'<<"Y="<<n.GetY( )<<endl;

m.SetX(n); // // 将类 n 中成员 y 的值赋给类 X 中的成员x //cout<<"X="<<m.GetX( )<<'\t'<<"Y="<<n.GetY( )<<endl;

}

由于类 X 的成员函数 :SetX(Y&) 是类 Y 的友元函数 , 因此可以访问类 Y 中的私有成员 y

输出结果 :X=5 Y=10X=10 Y=10

类 X 的成员函数 :SetX(Y&) 是类 Y 的友元函数 -> 对象 X m.SetX(n); 可以访问类 Y 中的私有成员 n.y

说明 : 如果不使用友元函数的方法 , //A 要改写成 : X::SetX(int a) {x=a}; //B 要改写成m.SetX(n.GetY())

12.1.3 将类说明为友元例 :12-3#include "iostream.h"class X { private : int x; public: X(int a) {x=a;} // 定义带参数的构造函数 int GetX( ){return x;} friend class Y; // 说明类 Y 是 X 的友元类 ,Y 类中

的成员函数都可以访问类 X 中的私有成员 };

class Y {private : int y; public: Y(int b=0) {y=b;} void Out(X &r) // Y 类中的成员函数

都可以访问类 X 中的私有成员 {cout<<"X="<<r.x<<'\t'<<"Y="<<y<<endl; }

};

void main() {

X m(5); Y n(10);

n.Out(m ); }输出结果 :X=5 Y=10

说明 :• 如果不说明 Y 是 X 的友元类 , 在类 Y 中成员函数 Out(X &r) 就错误• 如果不说明 Y 是 X 的友元类 , Cout<<”X=”<<r.x<<’\t’<<”Y=“<<y<<endl;句如何修改 ? 动用 r.GetX()12.2 虚函数多态性 : 用一个函数实现不同的功能编译时多态性 : 通过函数重载和运算符重载实现运行时多态性 : 通过继承和虚函数实现

12.2.1 虚函数 在基类中被说明成 virtual 的成员函数 , 或该类函数又派生出来的函数例 12-4:#include "iostream.h"class B {public: virtual void virfunc( ) {cout<<"Class B\n";}};

class D : public B{public: virtual void virfunc( ) {cout<<"Class D\n";}};class E: public B {public: virtual void virfunc( ) {cout<<"Class E\n";}};

void main(){ B b, *pb; D d; E e;

pb=&b;pb->virfunc( ); // 取 B 类 b 对象的地址时 , 就调用 B类中的虚函数pb=&d;pb->virfunc( ); // 取 D 类 d 对象的地址时 , 就调用 D类中的虚函数pb=&e;pb->virfunc( ); // 取 E 类 e 对象的地址时 , 就调用 E类中的虚函数

}

程序的输出结果为 :Class BClass DClass E

说明 :• 使用虚函数 , 可以使用同一个函数名 , 调用不同类中函数 .• 此多态性 , 是运行时的多态性• 不用指针 , 使用对象名也可以调用虚函数

12.3 静态成员 同类对象共享的类成员 , 称静态成员 ( 同类多个对象 , 要在内存中占用多片相同的存储区域 )12.3.1 静态数据成员例 12-5: 静态数据成员对输入输出的影响#include "iostream.h"class C { private : int d; static int s; // 定义静态成员 public: C(int a=0) // 定义带参数的构造函数

{ d=a; s++;

}

int GetD( ){return d;} int GetS( ){return s;} void SetD(int a ) {d=a;}; };int C::s=0; // 静态成员属于引用性说明,必须

在文件作用域之内说明一次void main() {C c[5]; // 定义 5 个对象,构造函数将连续执

行 5 次, s 的值将连续 5 次加 1 int i; for(i=0;i<5;i++) c[i].SetD(i+1); //5 个对象占据内存 5 个连续

区域 for(i=0;i<5;i++)

cout<<"c["<<i<<"].d="<<c[i].GetD( )<<'\t'<<"c["<<i<<"].s="<<c[i].GetS( )<<endl;

cout<<"There are "<<c[0].GetS( )<<"object created.\n";

}运行结果为 :c[0].d=1 c[0].s=5c[1].d=2 c[1].s=5c[2].d=3 c[2].s=5c[3].d=4 c[3].s=5c[4].d=5 c[4].s=5There are 5 object created

说明:静态数据成员无论多少对象,只占一个对象的数据成员区域

12.3.2 静态成员函数例 12-6#include "iostream.h"class C { private : int d; static int s; public: C(int a=0)

{d=a; s++;}

static int GetD( C&r){return r.d;} // 定义静态成员函数

static int GetS( ){return s;}void SetD(int a=0 ) {d=a;}; };

int C::s=0;void main(){C c[5];int i; for(i=0;i<5;i++) c[i].SetD(i+1);

for(i=0;i<5;i++)cout<<"c["<<i<<"].d="<<C::GetD(c[i] )<<'\t'<<"c["<<i<<"].s="<<C::GetS( )<<endl;

cout<<"There are "<<C::GetS( )<<"object created.\n";

}

// 通过类名字调用静态成员函数

说明 :1. 以上程序输出结果与 12.5 相同

2. C::GetD(c[i] ), 静态成员函数为类中所有对象所共有 , 该区域即归最后一次使用者。

3. 比较 C::GetD(c[i] ) 与 c[i].GetD( ) 差别

4. 数据的流动过程是理解类、对象、析构函数、友元、静态成员、派生、继承的关键