类中有关静态成员的使用
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
一 static的作用
1 什么是static?
static 是C++中很常用的修饰符,它被用来控制变量的存储方式和可见性。
2、为什么要引入static? 函数内部定义的变量,在程序执行到它的定义处时,编译器为它在栈上分配空间,大家知道,函数在栈上分配的空间在此函数执行结束时会释放掉,这样就产生了一个问题: 如果想将函数中此变量的值保存至下一次调用时,如何实现?最容易想到的方法是定义一个全局的变量,但定义为一个全局变量有许多缺点,最明显的缺点是破坏了此变量的访问范围(使得在此函数中定义的变量,不仅仅受此函数控制)。
3、什么时候用static? 需要一个数据对象为整个类而非某个对象服务,同时又力求不破坏类的封装性,即要求此成员隐藏在类的内部,对外不可见。
二,类的静态成员简介
静态局部变量
• 1.存放在静态存储区
• 2. 在两次函数调用期间保留原值仅在函数内部可见
• 3.可以被自动初始化为0
静态全局变量
•作用域:仅在变量所在的文件内
类的静态成员(C++特有的语法)
•至今为止,我们使用的成员变量和成员函数都由某个特定的对象调用。
但是,也许有些成员变量和成员函数,是属于整个类的。
•静态成员变量,必须在类声明之后,用::初始化;
•静态成员的值,和某一个具体对象是无关的。
•对于非静态成员来说,每个对象都有一个特定的值,每个对象都为自己非静态成员,在内存里保留一个位置。
•而静态成员,整个类只有一个备份
•静态成员函数的使用限制
• 1. 静态成员函数,被类的所有对象共享。
不是和某一个特定的对象。
而是和整个类相关联。
• 2.静态成员函数内部,不可以使用this指针。
因为this指针是指向每一个具体对象的。
所以说this指针本身就是非静态成员变量。
• 3.静态成员函数只能访问静态成员(包括静态成员函数和静态成员变量),而不能访问非静态成员。
但是非静态成员函数既可以访问非静态成员也可以访问静态成员。
• 4.静态成员函数,也可以有public和private。
private的静态成员函数,不能在外部用类名或对象名访问。
只能从类的内部被其他的静态成员函数访问。
•静态成员访问方式
•类名::静态成员名(推荐)
三,类的静态成员的深入研究
静态数据成员的使用方法和注意事项如下:
1、静态数据成员在定义或说明时前面加关键字static。
2、静态成员初始化与一般数据成员初始化不同。
静态数据成员初始化的格式如下:
<数据类型><类名>::<
静态数据成员名>=<值>
这表明:
(1) 初始
化在类体外进行,而前面不加static,以免与一般静态变量或对象相混淆。
(2) 初始化时不加该成员的访问权限控制符private,public等。
(3) 初始化时使用作用域运算符来标明它所属类,因此,静态数据成员是类的成员,而不是对象的成员。
3、静态数据成员是静态存储的,它是静态生存期,必须对它进行初始化。
4、引用静态数据成员时,采用如下格式: <类名>::<静态成员名> 如果静态数据成员的访问权限允许的话(即public的成员),可在程序中,按上述格式来引用静态数据成员。
静态成员函数 静态成员函数和静态数据成员一样,它们都属于类的静态成员,它们都不是对象成员。
因此,对静态成员的引用不需要用对象名。
在静态成员函数的实现中不能直接引用类中说明的非静态成员,可以引用类中说明的静态成员。
如果静态成员函数中要引用非静态成员时,可通过对象来引用。
下面看一个例子:
#include <iostream.h>
class Point
{
public:
void output()
{
}
static void init()
{ } };
void
main( void )
{
Point pt;
pt.init();
pt.output(); }
这样编译是不会有任何错误的。
下面这样看
#include
<iostream.h>
class Point
{
public:
void output()
{ }
static void init()
{ } };
void main( void )
{
Point::output();
}
这样编译会处错,错误信息:illegal call of non-static member function,为什么?
因为在没有实例化一个类的具体对象时,类是没有被分配内存空间的。
好的再看看下面的例子:
#include <iostream.h>
class Point
{
public:
void output()
{ }
static void init()
{ } };
void main( void )
{
Point::init();
}
这时编译就不会有错误,因为在类的定义时,它静态数据和成员函数就有了它的内存区,它不属于类的任何一个具体对象。
好的再看看下面的例子:
#include
<iostream.h>
class Point
{
public:
void output()
{ }
static void init()
{ x = 0;
y = 0;
}
private:
int x;
int y;
};
void main( void )
{
Point::init();
}
编译出错:
illegal reference to data member 'Point::x' in a static member function
illegal reference to data member 'Point::y' in a static member function
在一个静态成员函数里错误的引用了数据成员,
还是那个问题,静态成员(函数),不属于任何一个具体的对象,那么在类的具体对象声明之前就已经有了内存区,
而现在非静态数据成员还没有分配内存空间,那么这里调用就错误了,就好像没有声明一个变量却提前使用它一样。
也就是说在静态成员函数中不能引用非静态的成员变量。
好的再看看下面的例子:
#include
<iostream.h>
class Point
{
public:
void output()
{
x = 0;
y = 0;
init(); }
static void init()
{ }
private:
int x;
int y;
};
void main( void )
{
Point::init();
}
好的,这样就不会有任何错误。
这最终还是一个内存模型的问题, 任何变量在内存中有了自己的空间后,在其他地方才能被调用,否则就会出错。
好的再看看下面的例子:
#include <iostream.h>
class Point
{
public:
void output()
{ }
static void init()
{ x = 0;
y = 0;
}
private:
static int x;
static
int y;
};
void main( void )
{
Point::init();
}
编译:
Linking...
test.obj : error LNK2001: unresolved external symbol "private: static int Point::y" test.obj : error
LNK2001: unresolved external symbol "private: static int Point::x" Debug/Test.exe : fatal error LNK1120: 2 unresolved externals
执行link.exe 时出错.
可以看到编译没有错误,连接错误,这又是为什么呢?
这是因为静态的成员变量要进行初始化,可以这样:
#include
<iostream.h>
class Point
{
public:
void output()
{ }
static void init()
{ x = 0;
y = 0;
}
private:
static int x;
static int y;
};
int Point::x = 0;
int Point::y = 0;
void main( void )
{
Point::init();
}
在静态成员数据变量初始化之后就不会出现编译错误了。
再看看下面的代码:
#include <iostream.h>
class Point {
public:
void output()
{ }
static void init()
{ x = 0;
y = 0;
}
private:
static int x;
static
int y;
};
void main( void )
{
}
编译没有错误,为什么?
即使他们没有初始化,因为我们没有访问x,y,所以编译不会出错。
四. 如果想在静态成员函数内访问所有的成员,方法如下:
C++会区分两种类型的成员函数:静态成员函数和非静态成员函数。
这两者之间的一个重大区别是,静态成员函数
不接受隐含的this自变量。
所以,它就无法访问自己类的非静态成员。
在某些条件下,比如说在使用诸如pthread(它不支持类)此类的多线程库时,就必须使用静态的成员函数,因为其地址同C语言函数的地址兼容。
这种铜限制就迫使程序员要利用各种解决办法才能够从静态成员函数访问到非静态数据成员。
第一个解决办法是声明类的所有数据成员都是静态的。
运用这种方式的话,静态的成员函数就能够直接地访问它们,例如:
class Singleton
{
public:
static Singleton * instance();
private:
Singleton * p;
static Lock lock;
}; Singleton * Singleton::instance()
{
lock.getlock(); // fine, lock is static
if (!p)
p=new Singleton;
lock.unlock();
return p;
}
这种解决方法不适用于需要使用非静态数据成员的类。
访问非静态数据成员
将参照传递给需要考量的对象能够让静态的成员函数访问到对象的非静态数据:
class A
{
public:
static void func(A & obj);
int getval() const; //non-static member function
private:
int val;
};
静态成员函数func()会使用参照obj来访问非静态成员val。
voidA::func(A & obj)
{
int n = obj.getval();
}
将一个参照或者指针作为静态成员函数的自变量传递,就是在模仿自动传递非静态成员函数里this自变量这一行为。