静态成员
静态数据成员
class Sample
{
int a,b,c;//非静态数据成员
static int d;//静态数据成员
}s1,s2,s3;
静态数据成员的初始化必须在类体外进行。
int Sample::d=10;
注意
1、如果没有=10,那么静态数据成员的值被初始化为0。
2、变量名前要加类名限定,指定他所属的类
静态数据成员是类的所有对象共享的,而不是某个对象独享的,也可以说静态数据成员是属于类的。
静态数据成员的提出是为了解决对象之间的数据共享问题,一个对象给静态数据成员赋值之后,另一个对象可以读取该值。
静态成员函数
静态成员函数和静态数据成员一样,都是属于类的,而不是属于对象的。
在类体外调用公有静态成员函数:
<类名>::<静态成员函数名> (实参列表)
C++也允许通过对象名调用公有静态成员函数
<对象名>.<静态成员函数名> (实参列表)
同理,如果将一个静态数据成员定义成共有的,在类体外可以通过一下两种方式访问
<类名>::<静态成员成员名>
<对象名>.<静态成员成员名>
注意
如果静态数据成员或静态成员函数是私有的,在类体外不管是通过类名还是通过对象名都不能直接访问。
一般成员函数内部可以访问其他静态成员,而在静态成员函数中,只能直接访问类的其他静态成员,不能直接访问类的非静态成员。如果要想在静态成员函数中访问非静态成员,可以通过参数对象来实现,具体见下例;
#include <iostream>
using namespace std;
class Sample
{
int a;
static int b; // 定义私有静态数据成员
public:
static int c; // 定义公有静态数据成员
Sample(int x) { a = x; b += x; }
static void disp(Sample s) // A,定义静态成员函数
{
cout << "a=" << s.a << ", b=" << b << endl; // B
} // 续前行,访问非静态数据成员和静态数据成员
};
int Sample::b = 10; // C,初始化静态数据成员
int Sample::c = 20; // D,初始化静态数据成员
int main()
{
Sample s1(2), s2(3);
Sample::disp(s1); // E,可改写为s1.disp(s1);或s2.disp(s1);
Sample::disp(s2); // F,可改写为s1.disp(s2);或s2.disp(s2);
cout << "c=" << Sample::c << endl;
// G,Sample::c 可改写为 s1.c 或 s2.c
return 0;
}
友元
友元函数
类有很好的封装性和信息隐蔽性,即只有在类的成员函数中才能直接访问私有成员,在类外不能直接访问私有成员和保护成员(除非有公有函数接口)
这个时候,可以把函数定义为类的友元函数,见A行,这样就可以在友元函数内直接访问类的私有成员。
注意
1、友元函数不是类的成员函数,所以,可以把友元函数放在类的任意段:private、protected、public
2、书写友元函数的时候前面不用加类的限定,直接写friend后面的东西就好。
#include <iostream>
#include <cmath>
using namespace std;
class Point
{
int x, y;
public:
Point(int a = 0, int b = 0) : x(a), y(b) { }
void Show() { cout << "Point(" << x << ',' << y << ")\n"; }
int Getx() { return x; }
int Gety() { return y; }
friend double dist(Point&, Point&); // A
};
double dist(Point &p1, Point &p2)
{
return sqrt((p1.x - p2.x)*(p1.x - p2.x) + (p1.y - p2.y)*(p1.y - p2.y));//B
}
int main()
{
Point p1, p2(1, 1);
cout << dist(p1, p2) << endl;
return 0;
}
一个类的成员函数作为另一个类的友元函数
#include <iostream>
using namespace std;
class N; // A,类N的引用性说明
class M
{
int a, b;
public:
M(int x, int y) { a = x; b = y; }
void Print(){ cout << "a=" << a << '\t' << "b=" << b << endl; }
void Setab(N &); // B,Setab()是M类的成员函数,其参数是N类对象的引用
};
class N
{
int c, d;
public:
N(int x, int y) { c = x; d = y; }
void Print() { cout << "c=" << c << '\t' << "d=" << d << endl; }
friend void M::Setab(N&); // C,将类M的成员函数Setab()说明成本类的友元函数
};
void M::Setab(N &obj) // 类M的成员函数Setab( )是类N的友元函数,
{
a = obj.c; // D,因此在Setab( )中可直接访问类N的私有成员。
b = obj.d;
}
int main( )
{
M m(25, 40);
N n(55, 66);
cout << "m: "; m.Print();
cout << "n: "; n.Print();
m.Setab(n);
cout << "m: "; m.Print();
return 0;
}
运行结果:
m: a=25 b=40
n: a=55 d=66
m: a=55 b=66
友元类
当一个类作为另外一个类的友元时,意味着这个类的所有成员函数都是另一个类的成员函数
定义友元类:
class A
{
friend class B;
}
class B
{
xxxxxxxx
}
在B类所有成员函数中,均可以直接访问A类的私有成员
#include <iostream>
using namespace std;
class B; // 类的引用性说明
class A // 类中默认访问权限是私有的
{
int x;
void Disp() { cout << "x=" << x << endl; } // 私有成员函数
friend B; // 将B类说明成A类的友元类
};
class B
{
public:
void Set(int n)
{
A a;
a.x = n; //可访问A类对象的私有数据成员x
a.Disp(); //可访问A类对象的私有成员函数Disp( )
}
};
int main(void)
{
B b;
b.Set(3);
return 0;
}
运行结果:
x=3
常数据成员和常成员函数
常数据成员
常数据成员的值是常量,不能被修改。
常数据成员的初始化只能在类的构造函数的成员初始化列表中进行。
class Point
{
int x,y;
const int color;
public:
Point(int a=0,int b=0,int c=0):color(c)//构造函数
{
x=a;
y=b;
}
};
或者也可以写成
Point(int a=0,int b=0,int c=0):x(a),y(b),color(c){}
常成员函数
定义常成员函数的方法是在函数头的尾部、参数的右括号后面加关键字
注意
1、常成员函数只能读取类的数据成员,不能修改(比如不能赋值)
2、一般成员函数(指非const成员函数)可以修改除了常数据成员其他数据成员的值
#include <iostream>
using namespace std;
class Point
{
int x; // 一般数据成员
const int y; // 常数据成员
public:
Point(int a = 0, int b = 0) : x(a), y(b) { }
int fun() // A,一般成员函数
{
x = 5; // 修改一般数据成员x,合法
y = 6; // 修改常数据成员, 非法
return x + y; // 读取x和y, 合法
}
int fun() const // B,常成员函数
{
x = 5; // 修改一般数据成员x,非法
y = 6; // 修改常数据成员, 非法
return x + y; // 读取x和y, 合法
}
};
3、const参与重载函数的区分,见上例A行和B行。
4、常对象只能调用长常成员函数
#include <iostream>
using namespace std;
class Point
{
int x;
const int y;
public:
Point(int a = 0, int b = 0) : x(a), y(b) { }
int fun();
int fun() const; // 类中声明有关键字const
};
int Point::fun()
{
return x + y;
}
int Point::fun() const // 类外定义也必须有关键字const
{
return x - y;
}
int main()
{
Point p1(1, 8);
const Point p2(1, 8);
cout << p1.fun() << ',' ; // p1调用的是第1个fun()函数
cout << p2.fun() << endl; // p2调用的是第2个fun()函数
return 0;
}
5、如果要修改某个常对象数据成员的值,可以将数据成员定义为mutable型
6、常成员函数只能调用长成员函数,不能调用非const成员函数。