1.静态数据成员
class Employee{
private:
int id;
string name;
}
(1)如 id、name一样的非静态数据成员,它们在类的每一个对象中都拥有一个副本;
(2)若某个属性为整个类所共有,则采用static关键字来声明为静态成员,静态成员在每个类只有一个副本;
(3)由于静态数据成员不属于任何一个对象,因此可以通过类名对它进行访问,如:Point::x;
(4)静态数据成员的声明现在类的定义中进行引用性声明:static int count;之后在类外再加以定义(以这种方式专门为它们分配空间)
2.静态函数成员
(1)静态成员函数属于整个类,由同一个类的所有对象共同拥有,所以可以通过类名或对象名来调用,而非静态成员函数只能通过对象名来调用;静态成员函数可以直接访问该类的静态数据和函数成员,而访问非静态成员,必须通过对象名。(我的理解,public里面的函数其实不是每一个对象都存在一个与之相对应的副本,他只存在一个副本,但是因为需要确定this指针,所以需要用对象名调用);
class A {
public:
static void f(A a);
private:
int x;
};
void A::f(A a)
{
cout<<x;//对x的引用是错误的
cout<<a.x//正确
}
::是作用域符号,函数f所在的作用域是进入了A类"大门",但是又没进入A里面的所有"小房间",即x对于它来说,是懵逼的,需要指明x所在的“房间号”;
实例:
#include<iostream>
using namespace std;
class Point
{
public: //外部接口
Point(int x=0,int y=0):x(x),y(y)//构造函数
{
count++;
}
Point(Point &p)//复制构造函数
{
x=p.x;
y=p.y;
count++;
}
~Point()
{
count--;
}
int getX() const
{
return x;
}
int getY() const
{
return y;
}
static void showCount()
{
cout<<" Object count="<<count<<endl;
}
private:
int x,y;
static int count;
};
int Point::count=0;//静态数据成员的初始化
void main()
{
Point a(4,5);
cout<<"Point A:"<<a.getX()<<","<<a.getY();
Point::showCount();//用类调用静态函数成员
Point b(a);
cout<<"Point B:"<<b.getX()<<","<<b.getY();
Point::showCount();
}//析构函数~Point()会在调试到这里时,两次自动被调用,分别清除a和b
3.友元函数
定义:在类中用关键字friend修饰的非成员函数;
class Point
{
public:
Point(int x=0,int y=0):x(x),y(y){}
int getX() {return x;}
friend float dist(Point &p1,Point &p2);//友元函数声明
private:
int x;
}
float dist(Point &p1,Point &p2)
{
double x=p1.x-2;
return x;
}
函数dist不是Point的成员函数,但却可以通过对象名来访问类的私有和保护成员;
4.友元类
定义:若A类为B类的友元类,则A类的所有成员函数都自动成为B类的友元函数;
注意:(1)友元关系不能传递,即A->B,C->A,不能得出C->B;
(2)友元关系是单向的;
(3)友元关系是不被继承的(类B是类A的友元,类B的派生类并不会自动成为类A的友元);
4.常对象
常对象必须进行初始化,而且不能被更新:
class A a(3,4);
5.常成员函数
(1)若将一个对象说明为常对象,则通过该常对象只能调用它的常成员函数,而不能调用其他成员函数(常对象唯一的对外接口方式);
(2)在常成员函数调用期间,目的对象都被视为常对象,因此不能更新目的对象的数据成员,针对目的对象调用该类中没有用const修饰的成员函数;
(理解:其实1和2是相辅相成的,常目的对象不调用非常成员函数,是为了不让该常对象被修改,因为常成员函数不能更改目的对象的数据成员)
(3)const关键字可以用于对重载函数的区分:
void print();
void print() const;
若通过非const的对象调用该函数,编译器会选择void print();
6.常数据成员
class A
{
public:
......
private:
const int a;
static const int b;//静态常量
};
const int A::b=10;//静态数据成员在类外说明和初始化
//常数据成员只能通过初始化列表来获得初值
A::A(int i)::a(i){}
注意:类成员中的静态变量和常量都应该在类定义之外加以定义,但有一个例外:类的静态常量如果具有整数类型或枚举类型,即可直接在类定义中为它指定常量值,本例即可直接在类定义中写:
static const int b=10;
(理解:因为此时编译器会将程序对A::b的所有引用都替换成10,无需再为b分配空间,当需要用b时,从内存中调用b)
7.常引用
定义:常引用所引用的对象不能被更新,若用常引用作形参,便不会意外地发生对实参的改变:
flost dist (const Point &p1,const Point &p2);
答:全局变量的说明之前再加以static 就构成了静态的全局变量。全局变量本身就是静态存储方式,静态全局变量当然也是静态存储方式。这两者在存储方式上并无不同。这两者的区别虽在于非静态全局变量的作用域是整个源程序,当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。而静态全局变量则限制了其作用域,即只在定义该变量的源文件内有效,在同一源程序的其它源文件中不能使用它。由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用,因此可以避免在其它源文件中引起错误。从以上分析可以看出,把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域, 限制了它的使用范围。