静态数据成员
为什么要引入静态数据成员:主要原因是为了取代全局变量,让类的所有对象共享数据。
什么时候使用静态数据成员:定义类的各个对象公有的数据,如统计总数,平均数
优点:可以节省内存
类中的静态变量在内存中只存储一次,供所有对象所共有的,一旦一个对象改变其值,其他对象可以直接使用改变的值,这样可以提高效率和节省内存空间。
缺点:
由于静态变量时是类的多个对象共享。则在多线程的情况下,访问静态变量我们需要加一些异步机制,防止多个线程同时修改静态变量。
语法:
定义:static + 普通数据成员定义
初始化位置:必须在类外初始化,主函数前,而不能在类中进行初始化
注意:不能在类的初始化(在.h文件中)中对静态变量进行初始化,这样会导致重复定义
初始化方式:类型 类名::变量 = 值;------注意这时,前面不能加static
使用:
类外使用:
访问规则:public
使用方式:类对象名.静态数据成员名 或 类类型名::静态数据成员名
静态成员函数
为什么要引入静态数据成员:主要原因是为了取代全局函数,能在调用构造函数前(未初始化类之前)调用,通常CALLBACK函数中会用得到。
什么时候使用静态数据成员:
(1) 为了访问全局变量或类的静态数据成员
(2) 要调用一个函数,该函数是在构造对象之前使用,但是不能使用全局函数(不符合OO实现),而且类中非静态函数的调用需要使用对象,这时候需要使用静态成员函数。
语法:
定义:static + 普通成员函数定义
定义位置:可以在类内,也可以自类外。类外定义是不加static
使用:
类外使用:
访问规则:public
使用方式:类名::静态公有成员函数名(实参表);
注意:和普通的成员变量一样,如果是私有或受保护的,不能在类外直接使用
类中使用:
访问规则:public/protected/private(可以是任意方式定义)
使用方式:直接使用静态成员函数
性质:
1、没有this指针,不可以直接访问类中非非静态成员函数,常常用于访问类的静态数据和静态成员函数。
2、只属于一个类,可以再多个对象间共享。
3、一般情况下,静态成员函数不访问非静态成员函数,如果确实需要,则需要传入参数通过对象名访问。
4、静态成员函数不可以同时声明为virtual、const、volatile函数。
5、静态成员函数不能是虚函数
举例:
#include "iostream"
using namespace std;
class test
{
private:
int x;
int y;
public:
static int num;
static int Getnum()
{
x+=5; // 这行代码是错误的,静态成员函数不能调用非静态数据成员,要通过类的对象来调用。
num+=15;
return num;
}
};
int test::num = 10;
int main(void)
{
test a;
cout<<test::num<<endl; //10
test::num = 20;
cout<<test::num<<endl; //20
cout<<test::Getnum()<<endl; //35
cout<<a.Getnum()<<endl; //50
system("pause");
return 0;
}
通过上例可知: x+=5; // 这行代码是错误的
静态函数成员必须通过对象名来访问非静态数据成员。
另外,静态成员函数在类外实现时候无须加static关键字,否则是错误的。
若在类的体外来实现上述的那个静态成员函数,不能加static关键字,这样写就可以了:
int test::Getnum()
{
.........
}
1、static成员的所有者是类本身和对象,但是多有对象拥有一样的静态成员。从而在定义对象是不能通过构造函数对其进行初始化。
2、静态成员不能在类定义里边初始化,只能在class body外初始化。
3、静态成员仍然遵循public,private,protected访问准则。
4、静态成员函数没有this指针,它不能返回非静态成员,因为除了对象会调用它外,类本身也可以调用。
[cpp] view
plaincopy
- #include<iostream>
- using namespace std;
- class A
- {
- private:
- int i;
- static int j;
- public:
- A(int i=1)
- {
- this->i=i;
- }
- static void show();
- void show(const A&a);
- };
- int A::j=0; //类外初始化静态变量时,不要加static
- void A::show()//类外定义函数体时,不要加static ----静态函数访问静态成员
- {
- cout<<j<<endl;
- }
- void A::show(const A&a)//静态函数访问非静态成员,必须加参数
- {
- cout<<a.i<<endl;
- cout<<j<<endl;
- }
- void main()
- {
- A a;
- a.show();
- a.show(a);
- system("pause");
- }
注意:
1、类的静态成员函数不能访问非静态成员,但是非静态成员可以访问静态成员。
2、出现在类体外的函数定义不能指定关键字static;
3、静态成员之间可以相互访问,即静态成员函数访问静态数据成员和访问静态成员函数;
4、非静态成员函数可以任意地访问静态成员函数和静态数据成员;
5、静态成员函数不能访问非静态成员函数和非静态数据成员;
6、调用静态成员函数,可以用对象调用,也可以通过类调用
说明:
1、static与const的对比
变量的对比:
static:是为限定变量的作用域的,值是可以改变的
const:是表示变量是常量,是不可变的,提高程序健壮性。
函数的对比:
static:
修饰C中的函数:是为了限定作用域仅在本文件,其他文件不可用
修饰C++中的函数:是为了在对象创建之前做一些操作
const:
表示函数中的变量不可修改。
在类中声明static变量或者函数时,初始化时使用作用域运算符来标明它所属类,因此,静态数据成员是类的成员,而不是对象的成员,这样就出现以下作用:
(1)类的静态成员函数是属于整个类而非类的对象,所以它没有this指针,这就导致 了它仅能访问类的静态数据和静态成员函数。
(2)不能将静态成员函数定义为虚函数。
(3)由于静态成员声明于类中,操作于其外,所以对其取地址操作,就多少有些特殊 ,变量地址是指向其数据类型的指针 ,函数地址类型是一个“nonmember函数指针”。
(4)由于静态成员函数没有this指针,所以就差不多等同于nonmember函数,结果就 产生了一个意想不到的好处:成为一个callback函数,使得我们得以将C++和C-based X W indow系统结合,同时也成功的应用于线程函数身上。 (这条没遇见过)
(5)static并没有增加程序的时空开销,相反她还缩短了子类对父类静态成员的访问 时间,节省了子类的内存空间。
(6)静态数据成员在<定义或说明>时前面加关键字static。
(7)静态数据成员是静态存储的,所以必须对它进行初始化。 (程序员手动初始化,否则编译时一般不会报错,但是在Link时会报错误)
(8)静态成员初始化与一般数据成员初始化不同:
初始化在类体外进行,而前面不加static,以免与一般静态变量或对象相混淆;
初始化时不加该成员的访问权限控制符private,public等;
初始化时使用作用域运算符来标明它所属类;
所以我们得出静态数据成员初始化的格式:
<数据类型><类名>::<静态数据成员名>=<值>
(9)为了防止父类的影响,可以在子类定义一个与父类相同的静态变量,以屏蔽父类的影响。这里有一点需要注意:我们说静态成员为父类和子类共享,但我们有重复定义了静态成员,这会不会引起错误呢?不会,我们的编译器采用了一种绝妙的手法:name-mangling 用以生成唯一的标志。