新年愿望-贝博体育app网页版登录-贝博体育app苹果

1、什么是static?

st标签19atic是C++中很常用的修饰符,它被用来操控变量的存储方法和可见性。

2、为什么要引进static?
函数内部界说的变量,在程序履行到它标签3的界说处时,编译器为它在栈上分配空间,咱们知道,函数在栈上分配的空间在此函数履行完毕时会释放掉,这样就产生了一个问题: 假如想将函数中此变量的值保存至下一次调用时,怎么完成? 最简单想到的方法是界说一个大局的变量,但界说为一个大局变量有许多缺陷,最显着的缺陷是损坏了此变量的拜访规模(使得在此函数中界说的变量,不仅仅受此函数操控)。

3、什么时候用static?
需求一个数据目标为整个类而非某个目标服务,一起又力求不损坏类的封装性,即要求此成员躲藏在类的内部,对外不行见。

4、static的内部机制:
静态数据成员要在程序一开始运转时就有必要存在。由于函数在程序运转中被调用,所以静态数据成员不能在任何函数内分配空间和初始化。
这样,它的空间分配有三个或许的当地,一是作为类的外部接口的头文件,那里有类声明;二是类界说的内部完成,那里有类的成员函数界说;三是应用程序的main()函数前的大局数据声明和界说处。
静态数据成员要实践地分配空间,故不能在类的声明中界说(只能声明数据成员)。类声明只声明一个类的“尺度和标准”,并不进行实践的内存分配,所以在类声明中写成界说是过错的。它也不能在头文件中类声明的外部界说,由于那会形成在多个运用该类的源文件中,对其重复界说。
static被引进以奉告编译器,将变量存标签19储在程序的静态存储区而非栈上空间,静态
数据成员按界说呈现的先后次序依标签19次初始化,留意静态成员嵌套时,要确保所嵌套的成员现已初始化了。消除时的次序是初始化的反次序。

5、static的优势:
可以节约内存,由于它是一切目标所公有的,因而,对多个目标来说,静态数据成员只存储一处,供一切目标共用。静态数据成员的值对每个目标都是相同,但它的值是可以更新的。只要对静态数据成员的值更新一次,确保一切目标存取更新后的相同的值,这样可以进步时刻功率。

6、引证静态数据成员时,选用如下格局:
<类名>::<静态成员名>
假如静态数据成员的拜访权限答应的话(即public的成员),可在程序中,按上述格局来引证静态数据成员。

7、留意事项:
(1)类的静态成员函数是归于整个类而非类的目标,所以它没有this指针,这就导致了它仅能拜访类的静态数据和静态成员函数标签3。
(2)不能将静态成员函数界说为虚函数。
(3)由于静态成员声明于类中,操作于其外,所以对其取地址操作,就多少有些特别,变量地址是指向其数据类型的指针 ,函数地址类型是一个“nonmember函数指针”。

(4)由于静态成员函数没有this指针,所以就差不多等同于nonmember函数,成果就产生了一个意想不到的优点:成为一个callback函数,使得咱们得以将C++和C-based X Window体系结合,一起也成功的应用于线程函数身上。
(5)static并没有添加程序的时空开支,相反她还缩短了子类对父类静态成员的拜访时刻,节约了子类的内存空间。
(6)静态数据成员在<界说或阐明>时前面加关键字static。
(7)静态数据成员是静态存储的,所以有必要对它进行初始化。
(8)静态成员初始化与一般数据成员初始化不同:标签11
   初始化在类体外进行,而前面不加static,以免与一般静态变量或目标相混杂;
   初始化时不加该成员的拜访权限操控符private,public等;
   初始化时运用效果域运算符来标明它所属类;
   所以咱们得出静态数据成员初始化的格局:
<数据类型><类名>::<静态数据成员名>=<值>
(9)为了避免父类的影响,可以在子类界说一个与父类相同的静态变量,以屏蔽父类的影响。这儿有一点需求留意:咱们说静态成员为父类和子类同享,但咱们有重复界说了静态成员,这会不会引起过错呢?不会,咱们的编译器选用了一种绝妙的方法:name-mangling 用以生成仅有的标志。

静态数据成员
  在类中,静态成员可以完成多个目标之间的数据同享,而且运用静态数据成员还不会损坏躲藏的准则,即确保了安全性。因而,静态成员是类的一切目标中同享的成员,而不是某个目标的成员。
  运用静态数据成员可以节约内存,由于它是一切目标所公有的,因而,对多个目标来说,静态数据成员只存储一处,供一切目标共用。静态数据成员的值对每个目标都是相同,但它的值是可以更新的。只要对静态数据成员的值更新一次,确保一切目标存取更新后的相同的值,这样可以进步时刻功率。
  静态数据成员的运用方法和留意事项如下:
  1、静态数据成员在界说或阐明时前面加关键字static。
  2、静态成员初始化与一般数据成员初始化不同。静态数据成员初始化的格局如下:
    <数据类型><类名>::<静态数据成员名>=<值>
  这表明:

  (1) 初始化在类体外进行,而前面不加static,以免与一般静态变量或目标相混杂。
  (2) 初始化时不加该成员的拜访权限操控符private,public等。
  (3) 初始化时运用效果域运算符来标明它所属类,因而,静态数据成员是类的成员,而不是目标的成员。
  3、静态数据成员是静态存储的,它是静态生存期,有必要对它进行初始化。
  4、引证静态数据成员时,选用如下格局:
   <类名>::<静态成员名>
  假如静态数据成员的拜访权限答应的话(即public的成员),可在程序中,按上述格局来引证静态数据新年希望-贝博体育app网页版登录-贝博体育app苹果成员。

静态成员函数
  静态成员函数和静态数据成员相同,它们都归于类的静态成员,它们标签5都不是目标成员。因而,对静态成员的引证不需求用目标名。
  在静态成员函数的完成中不能直接引证类中阐明的非静态成员,可以引证类中阐明的静态成员。假如静态成员函数中要引证非静态成员时,可通过目标来引证。


下面看一个比如:
#include
class Point
{
public:
void output()
{
}
static void init()
{
}
};
void main( void )
{
Point pt;
pt.init();
pt.output();
}
这样编译是不会有任何过错的。
下面这样看
#include
class Point
{
public:
void output()
{
}
static void init()标签10
{
}
};
void main( void )
{
Point::output();
}
这样编译会处错,过错信息:illegal ca新年希望-贝博体育app网页版登录-贝博体育app苹果ll of non-static member function,为什么?
由于在没有实例化一个类的详细目标时,类是没有被分配内存空间的。
好的再看看下面的比如:
#include
class Point
{
public:
void output()
{
}
static void init()
{
}
};
void main( void )
{
Point::init();
}
这时编译就不会有过错,由于在类的界说时,它静态数据和成员函数就有了它的内存区,它不归于类的任何一个详细目标。
好的再看看下面的比如:
#标签19include
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
在一个静态成员函数里过错的引证了数据成员,
仍是那个问题,静态成员(函数),不归于任何一个详细的目标,那么在类的详细目标声明之前就现已有了内存区,而现在非静态数据成员还没有分配内存空间,那么这儿调用就过错了,就好像没有声明一个变量却提早运用它相同。
也就是说在静态成员函数中不能引证非静态的成员变量。

好的再看看下面新年希望-贝博体育app网页版登录-贝博体育app苹果的比如:
#include
class Point
{
public:
void output()
{
x = 0;
y = 0;
init();
}
static void init()
{

}
private:
int x;
int y;
};
void main( void )
{
Point::init();
}
好的,这样就不会有任何过错。这终究仍是一个内存模型的问题,
任何变量在内存中有了自己的空间后,在其他当地才干被调用,不然就会犯错。
好的再看看下面的比如:
#include
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 : er新年希望-贝博体育app网页版登录-贝博体育app苹果ror LNK2001: unresolved external symbol "private: static int Point::y新年希望-贝博体育app网页版登录-贝博体育app苹果"
test.obj : error LNK2001: unresolved external symbol "private: static int Point::x"
Debug/Test.exe : fatal error LNK1120: 2 unresolved externals
履行 link.exe 时犯错.
可以看到编译没有过错,衔接过错,这又是为什么呢?
这是由于静态的成员变量要进行初始化,可以这样:
#include
class新年希望-贝博体育app网页版登录-贝博体育app苹果 Point
{
public:
void output()
{
}
static void init()
{
x = 0;
y = 0;
}
private:
static int标签5 x;
static int y;
};
int Point::x = 0;
int Point::y = 0;
void main( void )
{
Point::init();
}
在静态成员数据变量初始化之后就不会呈现编译过错了。
再看看下面的代码:
#include
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++会区别两种类型的成员函标签20数:静态成员函数和非静态成员函数。这两者之间的一个严重区别是,静态成员函数不接受隐含的this自变量。所以,它就无法拜访自己类的非静态成员。

在某些条件下,比如说在运用比如pthread(它不支撑类)此类的多线程库时,就有必要运用静标签11态的成员函数,由于其标签17地址同C言语函数的地址兼容。这种铜约束就迫使程序员要运用各种处理方法才干够从静态成员函数拜访到非静态数据成员。

第一个处理新年希望-贝博体育app网页版登录-贝博体育app苹果方法是声明类的一切数据成员都是静态的。运用这种方法的话,静态的成员函数就可以直接地拜访它们,例如:

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);
intgetval() const; //non-static member function
private:
intval;
};

静态成员函数func()会运用参照obj来拜访非静态成员val。

voidA::func(A & obj)
{
int n = obj.getval();
}

将一个参照或许指针作为静态成员函数的自变量传递,就是在仿照主动传递非静态成员函数里this自变量这一行为。