第 11讲 静态成员和友元
教学目的与要求:
了解友元的声明和使用 。
掌握静态成员的特点和使用 。
教学内容提要:
1,静态成员;
2,友元;
3,常对象,常数据成员和常成员函数
教学重点:静态成员的特点和使用 。
教学难点:静态成员的特点和使用 。
教学进度,P85~ P96
教学过程:
静态成员 是满足在某些情况下数据共享的需求。
静态数据成员 是同一个类中所有对象共享的成员,而不是某一对象的成员。一个类的静态数据成员只存储在一处,供该类所有对象共享访问 。
静态成员的分类静态数据成员静态成员函数
【 11.1.1 静态数据成员 】
如果需要把某一数据成员声明为静态成员,只需在其前面 加关键字 static。
由于静态数据成员是静态存储的,它具有 静态生存期 。
注 由于在声明类时说明的静态数据成员只是一种引用性声明,而且在声明对象时,由于静态数据成员的特殊性,并不会为之分配内存 。要求 单独对静态数据成员进行定义性声明,以获得相应的存储空间。
【 11.1 静态成员 】
必须在具有文件作用域的某个地方进行。
其形式如下,类型 类名::静态数据成员名 =初始化值;
注 在定义静态数据成员时,由于关键字 static不是数据类型的一部分,不能加。
静态数据成员的使用
#include″iostream.h″
class A
{
public:
A(int x,int y)
{
a=x;
b=y;
}
~ A(){ }
void getXY()
例 11-1
{
cout<< ″X= ″<<a<< ′\ t ′<< ″Y= ″<<b<<endl; }
void getSUM()
{
sum=sum+a+b;
cout<< ″SUM= ″<<sum<<endl; }
private:
int a,b;
static int sum;
};
int A::sum=0; //静态数据成员的定义
void main()
{
A a1(1,2);
a1.getXY();
a1.getSUM();
A a2(3,4);
a2.getXY();
a2.getSUM();
}
X=1 Y=2
SUM=3
X=3 Y=4
SUM=10
(续)
a1 a
b
1
2
a2 a
b
3
4
sum 3100
例如,#include<iostream.h>class A{public:
static int x;
};
int A::x=0;
void main()
{
cout<<A::x<<endl;
A::x=10;
cout<<A::x<<endl;
}
在声明类时,让静态数据成员公有,则程序中可以 不通过该类的对象直接访问该数据 。对它的访问可以直接通过类名实现。
对于把类的静态数据成员 声明为私有 的情形,如果希望 不使用该类的对象来访问该数据,就必须据访问该数据的公有辅助成员函数声明为 静态的,
也即必须提供访问它的公有静态成员函数。
形式如下:
类名::静态数据成员名如果声明类时,在其中的某个成员函数的类型前加上关键字 static,则这个成员函数就是 静态成员函数 。 定义静态函数成员 也是解决在同一个类的所有对象之间 共享数据 的方法之一。
在静态成员函数的函数体中,可以 直接访问 所属类的静态成员,不能直接访问 非静态成员。要 访问非静态成员,须借助于对象名或指向对象的指针。
注 在类外定义静态成员函数,函数头前不能加关键字 static。
例 11-2 静态成员函数的使用
#include<iostream.h>
class A
{
public:
A(int x1,int x2)
{
x=x1;
【 11.1.2 静态成员函数 】
y=y+x2;
}
~ A(){}
static void fun1();
static void fun2(A a);
private:
int x;
static int y;
};
void A::fun1()
{
cout<< ″Y= ″<<y<<endl; //直接访问静态数据成员
}
void A::fun2(A a)
{
cout<< ″X= ″<<a.x<< ′\ t ′<< ″Y= ″<<y<<endl; //对非静态成员,
通过对象名访问静态成员函数的使用例 11-2
}
int A::y=0;
void main()
{
A a1(1,2);
a1.fun1(); //通过对象名访问
A::fun2(a1); //通过类名访问
A a2(3,4);
A::fun1(); //通过类名访问
a2.fun2(a2); //通过对象名访问
}
Y=2
X=1 Y=2
Y=6
X=3 Y=6
公有的静态成员函数 也可以通过相应的对象名来访问。公有静态成员函数还可以通过其所属的类名来访问。 静态成员函数不能声明为常成员函数 。
注
(续)
a1 x 1 a2 x 3
y 026
友元 提供了在不同类的成员函数之间、类的成员函数与一般函数之间进行数据共享的机制。 通过友元,一个普通函数或另一个类中的成员函数可以访问类中的私有成员和保护成员。
友元可以是函数,则该函数叫 友元函数。
可以是一个类,则该类叫 友元类。
在声明一个类时,可以使用关键字 friend把一个函数声明为 这个类的友元函数。
【 11.2.1 友元函数 】
友元函数并不是这个类的成员函数,但它可以在其函数体中 通过对象名访问 这个类的私有或保护成员。
注例 11-3 友元函数的使用
#include<iostream.h>
【 11.2 友元 】
class A //声明类 A
{
public:
void memberfun (int x);
};
class B //声明类 B
{
public:
B(){}
B(int x1)
{ x=x1; }
~ B(){ }
void getX()
{ cout<< ″X= ″<<x<<endl; }
private,int x;
};
友元函数的使用例 11-4
friend void fun(); //友元函数
friend void A::memberfun(int x); //友元函数
void A::memberfun(int x)
{
B b(0)
cout<< ″X= ″<<b.x<<endl;
b.x=x;
cout<< ″X= ″<<b.x<<endl;
}
void fun()
{
B b(10);
cout<< ″X= ″<<b.x<<endl;
}
void main()
{
fun();
A a;
a.memberfun(100);
}
X=10
X=0
X=100
(续)
如果需要把一个类(设为 A)中的所有成员函数都声明为另一个类(设为 B)
的 友元函数,则不必在类 B中对类 A中的成员函数一一加以说明。
直接把类 A声明为类 B的友元,这时称 类 A为类 B的友元类。简述友元声明也可以出现在类的私有或保护部分。
具体的说明形式如下:
class A
{
...
};
class B
{
...
friend class A;
...
};
注意事项:
● 友元关系 不具有交换性,也即友元关系具有单向的。若声明类 A为类 B的友元,并不表示类 B就是类 A的友元。
● 友元关系 不具有传递性,即若声明类
A为类 B的友元,类 B为类 C的友元,
并不表示类 A就是类 C的友元。
【 11.2.2 友元类 】
常对象的声明需要采用关键字 const,形式如下:
类名 const 对象名或
const 类名 对象名例如,class A{
public:
A(int i,int j);
...
private:
int a,b;
}
A::A(int i,int j)
{
a=i;
b=j;
}
A const a(1,2);
const A b(3,4);
说明,声明常对象时 同时 初始化,
并该对象在程序的其他地方 不能被重新赋值 。
这里声明的 a和 b都是常对象,
其值不可改变。
【 11.3 常对象、常成员函数与常数据成员 】
【 11.3.1 常对象 】
类的数据成员 如果其值在程序运行过程中不改变,也可以声明为常量。被声明为常量的类的数据成员称作 常数据成员 。
例 11-4 常数据成员的使用
#include<iostream.h>
class A
{
public:
A (int x,int y):a(x),c(y) //常数据成员只能通过初始化列表来初始化
{
}
~ A (){}
void getAB()
声明形式和一般符号常量 采用关键字 const声明的形式一样 。 不能在类内声明 这些常数据成员时直接赋初值,而 只能通过编写 带有初始化列表的构造函数来 初始化 。
简述
【 11.3.2 常数据成员 】
A=1 B=10 C=2
void getAB()
{cout<< ″A= ″<<a<< ′\ t ′<< ″B= ″<<b<< ′\ t ′<< ″C=
″<<c<<endl;
}
private:
const int a;
static const int b;
int c;
};
const int A::b=10; //静态常数据成员在类外定义并初始化
void main()
{
A a(1,2);
a.getAB();
}
常数据成员的使用例 11-4
使用关键字 const修饰的成员函数叫作常成员函数,关键字 const应放在函数参数表的括号之后。
形式如下,类型 函数名(参数表) const
类的常成员函数 不能改变成员变量的值,也不能调用该类中没有 const修饰的成员函数。 静态成员函数不能声明为常成员函数。
例 11-5 常成员函数的使用
#include<iostream.h>
class A
{
public:
A (int x,int y)
关键字 const是函数类型的组成部分,
在声明和定义这个函数时都 不能省去 。
【 11.3.3 常成员函数 】
通过常对象 b访问的是常成员函数 void getAB() const
通过对象 a访问的是普通成员函数 void getAB()
例 11-5
{
a=x;
b=y;
}
~ A (){}
void getAB();
void getAB() const;
private:
int a;
int b;
};
void A::getAB()
{
cout<< ″In void A::getAB()″<<endl;
cout<< ″A= ″<<a<< ′\ t ′<< ″B= ″<<b<<endl;
}
void A::getAB() const
{
常成员函数的使用
cout<< ″In void A::getAB() const ″<<endl;
cout<< ″A= ″<<a<< ′\ t ′<< ″B= ″<<b<<endl;
}
void main()
{
A a(1,2);
A const b(3,4);
a.getAB();
b.getAB();
}
In void A::getAB()
A=1 B=2
In void A::getAB() const
A=3 B=4
如果将一个对象声明为 常对象,则通过该对象 只能访问 它的常成员函数,
而 不能访问 其他成员函数。
(续)
1、
class M
{ public:
M(int a)
{ A=a;
B+=a;
}
static void fun( M m);
private:
int A;
static int B;
};
int M::B=10;
课堂练习
void M::fun( M m)
{ cout<<”A=”<<m.A<<endl;
cout<<”B=”<<B<<endl;
}
void main()
{
M P(6),Q(8);
M::fun(P);
Q.fun(Q);
}
A=6
B=24
A=8
B=24
P A 6 Q A 8
B 161024
小结:
1、静态数据成员和静态成员函数的特点和使用
2、友元函数和友元类的声明及作用
3、常对象、常数据成员和常成员函数的声明作业:
P107 3.16,3.17
教学目的与要求:
了解友元的声明和使用 。
掌握静态成员的特点和使用 。
教学内容提要:
1,静态成员;
2,友元;
3,常对象,常数据成员和常成员函数
教学重点:静态成员的特点和使用 。
教学难点:静态成员的特点和使用 。
教学进度,P85~ P96
教学过程:
静态成员 是满足在某些情况下数据共享的需求。
静态数据成员 是同一个类中所有对象共享的成员,而不是某一对象的成员。一个类的静态数据成员只存储在一处,供该类所有对象共享访问 。
静态成员的分类静态数据成员静态成员函数
【 11.1.1 静态数据成员 】
如果需要把某一数据成员声明为静态成员,只需在其前面 加关键字 static。
由于静态数据成员是静态存储的,它具有 静态生存期 。
注 由于在声明类时说明的静态数据成员只是一种引用性声明,而且在声明对象时,由于静态数据成员的特殊性,并不会为之分配内存 。要求 单独对静态数据成员进行定义性声明,以获得相应的存储空间。
【 11.1 静态成员 】
必须在具有文件作用域的某个地方进行。
其形式如下,类型 类名::静态数据成员名 =初始化值;
注 在定义静态数据成员时,由于关键字 static不是数据类型的一部分,不能加。
静态数据成员的使用
#include″iostream.h″
class A
{
public:
A(int x,int y)
{
a=x;
b=y;
}
~ A(){ }
void getXY()
例 11-1
{
cout<< ″X= ″<<a<< ′\ t ′<< ″Y= ″<<b<<endl; }
void getSUM()
{
sum=sum+a+b;
cout<< ″SUM= ″<<sum<<endl; }
private:
int a,b;
static int sum;
};
int A::sum=0; //静态数据成员的定义
void main()
{
A a1(1,2);
a1.getXY();
a1.getSUM();
A a2(3,4);
a2.getXY();
a2.getSUM();
}
X=1 Y=2
SUM=3
X=3 Y=4
SUM=10
(续)
a1 a
b
1
2
a2 a
b
3
4
sum 3100
例如,#include<iostream.h>class A{public:
static int x;
};
int A::x=0;
void main()
{
cout<<A::x<<endl;
A::x=10;
cout<<A::x<<endl;
}
在声明类时,让静态数据成员公有,则程序中可以 不通过该类的对象直接访问该数据 。对它的访问可以直接通过类名实现。
对于把类的静态数据成员 声明为私有 的情形,如果希望 不使用该类的对象来访问该数据,就必须据访问该数据的公有辅助成员函数声明为 静态的,
也即必须提供访问它的公有静态成员函数。
形式如下:
类名::静态数据成员名如果声明类时,在其中的某个成员函数的类型前加上关键字 static,则这个成员函数就是 静态成员函数 。 定义静态函数成员 也是解决在同一个类的所有对象之间 共享数据 的方法之一。
在静态成员函数的函数体中,可以 直接访问 所属类的静态成员,不能直接访问 非静态成员。要 访问非静态成员,须借助于对象名或指向对象的指针。
注 在类外定义静态成员函数,函数头前不能加关键字 static。
例 11-2 静态成员函数的使用
#include<iostream.h>
class A
{
public:
A(int x1,int x2)
{
x=x1;
【 11.1.2 静态成员函数 】
y=y+x2;
}
~ A(){}
static void fun1();
static void fun2(A a);
private:
int x;
static int y;
};
void A::fun1()
{
cout<< ″Y= ″<<y<<endl; //直接访问静态数据成员
}
void A::fun2(A a)
{
cout<< ″X= ″<<a.x<< ′\ t ′<< ″Y= ″<<y<<endl; //对非静态成员,
通过对象名访问静态成员函数的使用例 11-2
}
int A::y=0;
void main()
{
A a1(1,2);
a1.fun1(); //通过对象名访问
A::fun2(a1); //通过类名访问
A a2(3,4);
A::fun1(); //通过类名访问
a2.fun2(a2); //通过对象名访问
}
Y=2
X=1 Y=2
Y=6
X=3 Y=6
公有的静态成员函数 也可以通过相应的对象名来访问。公有静态成员函数还可以通过其所属的类名来访问。 静态成员函数不能声明为常成员函数 。
注
(续)
a1 x 1 a2 x 3
y 026
友元 提供了在不同类的成员函数之间、类的成员函数与一般函数之间进行数据共享的机制。 通过友元,一个普通函数或另一个类中的成员函数可以访问类中的私有成员和保护成员。
友元可以是函数,则该函数叫 友元函数。
可以是一个类,则该类叫 友元类。
在声明一个类时,可以使用关键字 friend把一个函数声明为 这个类的友元函数。
【 11.2.1 友元函数 】
友元函数并不是这个类的成员函数,但它可以在其函数体中 通过对象名访问 这个类的私有或保护成员。
注例 11-3 友元函数的使用
#include<iostream.h>
【 11.2 友元 】
class A //声明类 A
{
public:
void memberfun (int x);
};
class B //声明类 B
{
public:
B(){}
B(int x1)
{ x=x1; }
~ B(){ }
void getX()
{ cout<< ″X= ″<<x<<endl; }
private,int x;
};
友元函数的使用例 11-4
friend void fun(); //友元函数
friend void A::memberfun(int x); //友元函数
void A::memberfun(int x)
{
B b(0)
cout<< ″X= ″<<b.x<<endl;
b.x=x;
cout<< ″X= ″<<b.x<<endl;
}
void fun()
{
B b(10);
cout<< ″X= ″<<b.x<<endl;
}
void main()
{
fun();
A a;
a.memberfun(100);
}
X=10
X=0
X=100
(续)
如果需要把一个类(设为 A)中的所有成员函数都声明为另一个类(设为 B)
的 友元函数,则不必在类 B中对类 A中的成员函数一一加以说明。
直接把类 A声明为类 B的友元,这时称 类 A为类 B的友元类。简述友元声明也可以出现在类的私有或保护部分。
具体的说明形式如下:
class A
{
...
};
class B
{
...
friend class A;
...
};
注意事项:
● 友元关系 不具有交换性,也即友元关系具有单向的。若声明类 A为类 B的友元,并不表示类 B就是类 A的友元。
● 友元关系 不具有传递性,即若声明类
A为类 B的友元,类 B为类 C的友元,
并不表示类 A就是类 C的友元。
【 11.2.2 友元类 】
常对象的声明需要采用关键字 const,形式如下:
类名 const 对象名或
const 类名 对象名例如,class A{
public:
A(int i,int j);
...
private:
int a,b;
}
A::A(int i,int j)
{
a=i;
b=j;
}
A const a(1,2);
const A b(3,4);
说明,声明常对象时 同时 初始化,
并该对象在程序的其他地方 不能被重新赋值 。
这里声明的 a和 b都是常对象,
其值不可改变。
【 11.3 常对象、常成员函数与常数据成员 】
【 11.3.1 常对象 】
类的数据成员 如果其值在程序运行过程中不改变,也可以声明为常量。被声明为常量的类的数据成员称作 常数据成员 。
例 11-4 常数据成员的使用
#include<iostream.h>
class A
{
public:
A (int x,int y):a(x),c(y) //常数据成员只能通过初始化列表来初始化
{
}
~ A (){}
void getAB()
声明形式和一般符号常量 采用关键字 const声明的形式一样 。 不能在类内声明 这些常数据成员时直接赋初值,而 只能通过编写 带有初始化列表的构造函数来 初始化 。
简述
【 11.3.2 常数据成员 】
A=1 B=10 C=2
void getAB()
{cout<< ″A= ″<<a<< ′\ t ′<< ″B= ″<<b<< ′\ t ′<< ″C=
″<<c<<endl;
}
private:
const int a;
static const int b;
int c;
};
const int A::b=10; //静态常数据成员在类外定义并初始化
void main()
{
A a(1,2);
a.getAB();
}
常数据成员的使用例 11-4
使用关键字 const修饰的成员函数叫作常成员函数,关键字 const应放在函数参数表的括号之后。
形式如下,类型 函数名(参数表) const
类的常成员函数 不能改变成员变量的值,也不能调用该类中没有 const修饰的成员函数。 静态成员函数不能声明为常成员函数。
例 11-5 常成员函数的使用
#include<iostream.h>
class A
{
public:
A (int x,int y)
关键字 const是函数类型的组成部分,
在声明和定义这个函数时都 不能省去 。
【 11.3.3 常成员函数 】
通过常对象 b访问的是常成员函数 void getAB() const
通过对象 a访问的是普通成员函数 void getAB()
例 11-5
{
a=x;
b=y;
}
~ A (){}
void getAB();
void getAB() const;
private:
int a;
int b;
};
void A::getAB()
{
cout<< ″In void A::getAB()″<<endl;
cout<< ″A= ″<<a<< ′\ t ′<< ″B= ″<<b<<endl;
}
void A::getAB() const
{
常成员函数的使用
cout<< ″In void A::getAB() const ″<<endl;
cout<< ″A= ″<<a<< ′\ t ′<< ″B= ″<<b<<endl;
}
void main()
{
A a(1,2);
A const b(3,4);
a.getAB();
b.getAB();
}
In void A::getAB()
A=1 B=2
In void A::getAB() const
A=3 B=4
如果将一个对象声明为 常对象,则通过该对象 只能访问 它的常成员函数,
而 不能访问 其他成员函数。
(续)
1、
class M
{ public:
M(int a)
{ A=a;
B+=a;
}
static void fun( M m);
private:
int A;
static int B;
};
int M::B=10;
课堂练习
void M::fun( M m)
{ cout<<”A=”<<m.A<<endl;
cout<<”B=”<<B<<endl;
}
void main()
{
M P(6),Q(8);
M::fun(P);
Q.fun(Q);
}
A=6
B=24
A=8
B=24
P A 6 Q A 8
B 161024
小结:
1、静态数据成员和静态成员函数的特点和使用
2、友元函数和友元类的声明及作用
3、常对象、常数据成员和常成员函数的声明作业:
P107 3.16,3.17