static顾名思义是一个静态的含义。在此我想谈谈相关的系统statickeyword角色,当然,这主要是对语言的发展C与C++角色,在信息方面的作用等方面,请另找。在评论中肯定有不恰当,请大胆地抛砖。手软,文中的内容引用了不少网上的资料。

static从宏观上讲主要有两种使用方法,一、是面向过程设计;二是面向对象设计。前主要是涉及变量与函数的使用方法。后者呢包括前者使用方法的同一时候。还有在类中的使用方法。

一、 面向过程设计中的static(C语言)

在讲面向过程设计中的static使用方法时先搞点插曲,从历史上讲。C程序一直由以下几部分组成:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd2VucmVuaHVhMDg=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

正文段

CPU运行的机器指令部分。通常,正文段是可共享的。所以即使是经常环境指针环境表环境字符串运行的程序(如文本编辑程序、C编译程序、s h e l l等)在存储器中也仅仅需有一个副本,另外,正文段经常是仅仅读的,以防止程序因为意外事故而改动其自身的指令。

初始化数据段

通常将此段称为数据段,它包括了程序中需赋初值的变量。初始化 的全局变量和 静态变量存放在这里。

比如。C程序中不论什么函数之外的说明:int maxcount = 99; 使此变量以初值存放在初始化数据段中。

a.初始化的全局变量

b.初始化的静态变量

非初始化数据段

通常将此段称为bss段,这一名称来源于早期汇编程序的一个操作符,意思是“block started by symbol(由符号開始的块)”,未初始化的全局变量 和静态变量存放在这里。在程序開始运行之前。内核将此段初始化为0。函数外的说明:long sum[1000] ; 使此变量存放在非初始化数据段中。

a.未初始化的全局变量

b.未初始化的静态变量

须要由程序猿分配释放管理,若程序猿不释放,程序结束时可能由OS回收。

通常在堆中进行动态存储分配。

如程序中的malloc, calloc,realloc等函数都从这里面分配。堆是从下向上分配的。

由编译器自己主动分配释放管 理。

局部变量及每次函数调用时返回地址、以及调用者的环境信息(比如某些机器寄存器)都存放在栈中。新被调用的函数在栈上为其自己主动和暂时变量分配存储空间。通过以这样的方式使用栈。C函数能够递归调用。

递归函数每次调用自身时,就使用一个新的栈帧。因此一个函数调用实例中的变量绝不会影响还有一个函数调用实例中的变量。

a.局部变量

b.函数调用时返回地址

c.调用者的环境信息(比如某些机器寄存器)

在这我先把static的内部机制与优势先提到前面来讲述,本来想放到面向对象设计中来讲,可是它的重要性改变了初衷:

static的内部机制:

静态数据成员要在程序一開始执行时就必须存在。

由于函数在程序执行中被调用,所以静态数据成员不能在不论什么函数内分配空间和初始化。

这样,它的空间分配有三个可能的地方,一是作为类的外部接口的头文件,那里有类声明;二是类定义的内部实现。那里有类的成员函数定义;三是应用程序的main()函数前的全局数据声明和定义处。

静态数据成员要实际地分配空间,故不能在类的声明中定义(仅仅能声明数据成员)。类声明仅仅声明一个类的“尺寸和规格”,并不进行实际的内存分配,所以在类声明中写成定义是错误的。它也不能在头文件里类声明的外部定义,由于那会造成在多个使用该类的源文件里。对其反复定义。

static被引入以告知编译器。将变量存储在程序的静态存储区而非栈上空间。静态数据成员按定义出现的先后顺序依次初始化,注意静态成员嵌套时,要保证所嵌套的成员已经初始化了。消除时的顺序是初始化的反顺序。

static的优势:

能够节省内存,由于它是全部对象所公有的。因此,对多个对象来说。静态数据成员仅仅存储一处,供全部对象共用。静态数据成员的值对每一个对象都是一样。但它的值是能够更新的。

仅仅要对静态数据成员的值更新一次,保证全部对象存取更新后的同样的值。这样能够提高时间效率。

static局部变量

静态局部变量属于静态存储方式。它具有下面特点:

(1)静态局部变量 在函数内定义它的生存期为 整个程序生命周期,可是其 作用域仍与 自己主动变量同样 ,仅仅能在定义该变量的函数内使用该变量。

退出该函数后,虽然该变量还继续存在。但不能使用它。

(2)对基本类型的静态局部变量若在声明时未赋以初值,则系统自己主动赋予0值 。

而对自己主动变量不赋初值,则其值是不定的。

依据静态局部变量的特点,能够看出它是一种生存期为整个程序生命周期。尽管离开定义它的函数后不能使用,但如再次调用定义它的函数时,它又可继续使用。并且保存了前次被调用后留下的值。因此,当多次调用一个函数且要求在调用之间保留某些变量的值时,可考虑採用静态局部变量。尽管用全局变量也能够达到上述目的。但全局变量有时会造成意外的副作用。因此仍以採用局部静态变量为宜。

#include <stdio.h>
#include <stdlib.h> void Test()
{
static int tmpValue = 0;
printf("value = %d\n", ++tmpValue);
} int main()
{
for(int index = 0; index < 50; ++index)
{
Test()
}
getchar();
return 0;
}

全局变量

全局变量(外部变量)的说明之前再冠以static 就构成了静态的全局变量。

全局变量本身就是静态存储方式,静态全局变量当然也是静态存储方式。 这两者在存储方式上并无不同。

这两者的差别在于:

(1). 非静态全局变量 的作用域是整个源程序 ,当一个源程序由多个源文件组成时。非静态的全局变量在各个源文件里都是有效的。

(2). 而静态全局变量 则限制了其作用域,即仅仅在定义该变量的源文件内有效。在同一源程序的其他源文件里不能使用它。

因为静态全局变量的作用域局限于 一个源文件内 ,仅仅能为该源文件内的函数公用, 因此能够避免在其他源文件里引起错误。

从以上分析能够看出,把全局变量改变为静态变量后是改变了它的作用域。限制了它的使用范围 。

static 函数

假设在一个源文件里定义的函数,仅仅能被本文件里的函数调用。而不能被同一程序其他文件里的函数调用,这样的函数称为static函数与称为静态函数。

定义一个static函数。仅仅需在函数类型前再加一个“static”keyword就可以。例如以下所看到的:

static 函数类型 函数名(函数參数表) {……}

keyword“static”。译成中文就是“静态的”,所以内部函数又称静态函数。

但此处“static”的含义不是指存储方式,而是指对函数的作用域仅局限于本文件 。

使用内部函数的优点是:不同的人编写不同的函数时。不用操心自定义的函数。是否会与其他文件里的函数同名,由于同名也没有关系。

二、面向对象设计中的static(C++语言)

static 数据成员

在类内数据成员的声明前加上keywordstatic,该数据成员就是类内的静态数据成员。

先举一个静态数据成员的样例。

#include <stdio.h>
#include <stdlib.h> class Test
{
public:
Test() {}
~Test() {} Test(const Test& t)
{
if(this != &t)
{
this->m_nTest1 = t.m_nTest1;
this->m_nTest2 = t.m_nTest2;
this->m_nTest3 = t.m_nTest3;
}
} Test& operator=(const Test& t)
{
if(this != &t)
{
this->m_nTest1 = t.m_nTest1;
this->m_nTest2 = t.m_nTest2;
this->m_nTest3 = t.m_nTest3;
}
return *this;
} void PrintOut()
{
//printf("test_1 = %d test_2 = %d test_3 = %d\n",m_nSTest1, m_nSTest2, m_nSTest3);//错误
printf("test_1 = %d test_2 = %d test_3 = %d\n",m_nTest1, m_nTest2, m_nTest3);
} static void PrintStatic()
{
printf("test_1 = %d test_2 = %d test_3 = %d\n",m_nSTest1, m_nSTest2, m_nSTest3);
//printf("test_1 = %d test_2 = %d test_3 = %d\n",m_nTest1, m_nTest2, m_nTest3);//错误
} public:
int m_nTest1;
static int m_nSTest1; protect:
int m_nTest2;
static int m_nSTest2; private:
int m_nTest3;
static int m_nSTest3;
};
int Test::m_nSTest1 = 10;
int Test::m_nSTest2 = 20;
int Test::m_nSTest3 = 30; int Test::m_nSTest1 = 10;
int main()
{
Test t;
t.PrintOut();
//t.PrintStatic();//错误
Test::PrintStatic();
getchar();
return 0;
}

static数据成员有下面特点:

(1). 对于非static数据成员。每一个类对象都有自己的拷贝。而static数据成员被当作是类的成员。不管这个类的对象被定义了多少个,静态数据成员在程序中也仅仅有一份拷贝 ,由该类型的全部对象共享訪问。也就是说。静态数据成员是该类的全部对象所共同拥有的。

对该类的多个对象来说,静态数据成员仅仅分配一次内存,供全部对象共用。

(2). 静态数据成员存储在全局数据区。

静态数据成员定义时才分配空间,所以不能在类声明中定义。在上例中。语句int Test::m_nSTest1= 10;是定义静态数据成员。

(3). 静态数据成员和普通数据成员一样遵从public,protected,private訪问规则。

(4). 由于静态数据成员在全局数据区分配内存。属于本类的全部对象共享,所以,它不属于特定的类对象,在没有产生类对象时其作用域就可见,即在没有产生类的实例时。我们就能够操作它;

(5). 静态数据成员初始化与一般数据成员初始化不同。静态数据成员初始化的格式为:<数据类型><类名>::<静态数据成员名>=<值> 如:int Test::m_nSTest1 = 10;

(6). 类的静态数据成员有两种訪问形式:<类对象名>.<静态数据成员名> 或 <类类型名>::<静态数据成员名>

(7). 静态数据成员主要用在各个对象都有同样的某项属性的时候。比方对于一个存款类,每一个实例的利息都是同样的。所以,应该把利息设为存款类的静态数据成员。这有两个优点,第一。无论定义多少个存款类对象。利息数据成员都共享分配在全局数据区的内存。所以节省存储空间。第二,一旦利息须要改变时,仅仅要改变一次,则全部存款类对象的利息全改变过来了;

(8). 同全局变量相比。使用静态数据成员有两个优势:

a. 静态数据成员没有进入程序的全局名字空间。因此不存在与程序中其他全局名字冲突的可能性;

b. 能够实现信息隐藏。静态数据成员能够是private成员,而全局变量不能。

static成员函数

#include <stdio.h>
#include <stdlib.h> class Test
{
public:
Test() {}
~Test() {} Test(const Test& t)
{
if(this != &t)
{
this->m_nTest1 = t.m_nTest1;
this->m_nTest2 = t.m_nTest2;
this->m_nTest3 = t.m_nTest3;
}
} Test& operator=(const Test& t)
{
if(this != &t)
{
this->m_nTest1 = t.m_nTest1;
this->m_nTest2 = t.m_nTest2;
this->m_nTest3 = t.m_nTest3;
}
return *this;
} void PrintOut()
{
//printf("test_1 = %d test_2 = %d test_3 = %d\n",m_nSTest1, m_nSTest2, m_nSTest3);//错误
printf("test_1 = %d test_2 = %d test_3 = %d\n",m_nTest1, m_nTest2, m_nTest3);
} static void PrintStatic()
{
printf("test_1 = %d test_2 = %d test_3 = %d\n",m_nSTest1, m_nSTest2, m_nSTest3);
//printf("test_1 = %d test_2 = %d test_3 = %d\n",m_nTest1, m_nTest2, m_nTest3);//错误
} public:
int m_nTest1;
static int m_nSTest1; protect:
int m_nTest2;
static int m_nSTest2; private:
int m_nTest3;
static int m_nSTest3;
};
int Test::m_nSTest1 = 10;
int Test::m_nSTest2 = 20;
int Test::m_nSTest3 = 30; int Test::m_nSTest1 = 10;
int main()
{
Test t;
t.PrintOut();
//t.PrintStatic();//错误
Test::PrintStatic();
getchar();
return 0;
}

static 成员函数,它为类的所有服务而不是为某一个类的详细对象服务。普通的成员函数一般都隐含了一个this指针,由于普通成员函数总是详细的属于某个类的详细对象的。

通常情况下,this是缺省的。

如函数fn()实际上是this->fn()。可是与普通函数相比,静态成员函数由于不是与不论什么的对象相联系。因此它不具有this指针 。从这个意义上讲。它无法訪问属于类对象的no-static数据成员。也无法訪问no-static成员函数。它仅仅能调用其余的静态成员函数

关于静态成员函数,能够总结为下面几点:

(1). 出如今类体外的函数定义不能指定keywordstatic ;

(2). static成员之间能够相互訪问 ,包含static成员函数訪问static数据成员和訪问static成员函数;

(3). 非静态成员函数能够随意地訪问静态成员函数和静态数据成员;

(4). 静态成员函数不能訪问非静态成员函数和非静态数据成员,仅仅能訪问静态的;

(5). 因为没有this指针的额外开销。因此静态成员函数与类的全局函数相比速度上会有少许的增长;

(6). 调用静态成员函数。能够用成员訪问操作符(.)和(->)为一个类的对象或指向类对象的指针调用静态成员函数,也能够直接使用例如以下格式:

<类名>::<静态成员函数名>(<參数表>)

如:Test::PrintStatic(),调用类的静态成员函数。

可是,一样要遵从public,protected,private訪问规则。

附 public,protected,private訪问规则

第一:private, public, protected訪问标号的訪问范围。

private:仅仅能由1.该类中的函数、2.其友元函数訪问。

不能被不论什么其它訪问。该类的对象也不能訪问。

protected:能够被1.该类中的函数、2.子类的函数、以及3.其友元函数訪问。

但不能被该类的对象訪问。

public:能够被1.该类中的函数、2.子类的函数、3.其友元函数訪问,也能够由4.该类的对象訪问。

注:友元函数包含3种:设为友元的普通的非成员函数;设为友元的其它类的成员函数;设为友元类中的全部成员函数。

第二:类的继承后方法属性变化。

private属性不可以被继承。

使用private继承,父类的protected和public属性在子类中变为private;

使用protected继承,父类的protected和public属性在子类中变为protected;

使用public继承,父类中的protected和public属性不发生改变;

例如以下所看到的:

public:           protected:       private:

public继承            public            protected       不可用

protected继承         protected         protected       不可用

private继承           private          private          不可用

protected继承和private继承能减少訪问权限。

为了进一步理解三种不同的继续方式在其成员的可见性方面的差别,以下从三种不同角度进行讨论。

  对于公有继续方式:

  (1) 基类成员对其对象的可见性:

  公有成员可见,其它不可见。这里保护成员同于私有成员。

  (2) 基类成员对派生类的可见性:

  公有成员和保护成员可见,而私有成员不可见。

这里保护成员同于公有成员。

  (3) 基类成员对派生类对象的可见性:

  公有成员可见。其它成员不可见。

  所以,在公有继续时。派生类的对象能够訪问基类中的公有成员。派生类的成员函数能够訪问基类中的公有成员和保护成员。这里,一定要区分清楚派生类的对象和派生类中的成员函数对基类的訪问是不同的。

  对于私有继续方式:

  (1) 基类成员对其对象的可见性:

  公有成员可见,其它成员不可见。

  (2) 基类成员对派生类的可见性:

  公有成员和保护成员是可见的,而私有成员是不可见的。

  (3) 基类成员对派生类对象的可见性:

  全部成员都是不可见的。

  所以,在私有继续时,基类的成员仅仅能由直接派生类訪问。而无法再往下继续。

  对于保护继续方式:

  这样的继续方式与私有继续方式的情况同样。两者的差别仅在于对派生类的成员而言,对基类成员有不同的可见性。

  上述所说的可见性也就是可訪问性。关于可訪问性还有另的一种说法。

这样的规则中,称派生类的对象对基类訪问为水平訪问。称派生类的派生类对基类的訪问为垂直訪问。

  一般规则例如以下:

  公有继续时,水平訪问和垂直訪问对基类中的公有成员不受限制;

  私有继续时,水平訪问和垂直訪问对基类中的公有成员也不能訪问;

  保护继续时。对于垂直訪问同于公有继续,对于水平訪问同于私有继续。

  对于基类中的私有成员。仅仅能被基类中的成员函数和友元函数所訪问。不能被其它的函数訪问。

  基类与派生类的关系

  不论什么一个类都能够派生出一个新类,派生类也能够再派生出新类。因此。基类和派生类是相对而言的。

  基类与派生类之间的关系能够有例如以下几种描写叙述:

  1. 派生类是基类的详细化

  类的层次通常反映了客观世界中某种真实的模型。在这样的情况下。不难看出:基类是对若干个派生类的抽象,而派生类是基类的详细化。基类抽取了它的派生类的公共特征,而派生类通过添加行为将抽象类变为某种实用的类型。

  2. 派生类是基类定义的延续

  先定义一个抽象基类,该基类中有些操作并未实现。然后定义非抽象的派生类,实现抽象基类中定义的操作。

比如,虚函数就属此类情况。这时。派生类是抽象的基类的实现。就可以看成是基类定义的延续。

这也是派生类的一种经常用法。

  3. 派生类是基类的组合

  在多继续时。一个派生类有多于一个的基类。这时派生类将是全部基类行为的组合。

  派生类将其本身与基类差别开来的方法是加入数据成员和成员函数。因此,继续的机制将使得在创建新类时,仅仅需说明新类与已有类的差别。从而大量原有的程序代码都能够复用,所以有人称类是“可重用的软件组件”。

版权声明:本文博客原创文章。博客,未经同意,不得转载。

C++ 中间statickeyword的更多相关文章

  1. Java中的statickeyword具体解释

    1.statickeyword主要有2个作用: ①为某特定的数据类型或者对象分配单一的存储空间.而与创建对象的个数无关. ②在不创建对象的情况下能够直接通过类名来直接调用方法或者使用类的属性. 2.s ...

  2. statickeyword于C和C++用法

    一.C语言statickeyword两个使用 1).一个功能修改内部使用的变量,函数内的静态变量.这些变量的寿命比功能不再,它是具有一定的函数"状态",使用静态变量的作用通常是不可 ...

  3. [javase学习笔记]-8.3 statickeyword使用的注意细节

    这一节我们看静态在使用过程中应注意的几个细节. 上一节我们在学习成员变量与静态变量的差别时,对于两种变量的调用方式不同一时候出现了"无法从静态上下文中訪问非静态变量"的错误.这个问 ...

  4. [javase学习笔记]-8.1 statickeyword之特点

    这一节我们来学习java语言中一个新的keyword就是statickeyword. 当然对于每个keyword,我们都要明白的是它有什么作用,怎么用.我们先来看一个样例: class Person ...

  5. 《Java程序猿面试笔试宝典》之Statickeyword有哪些作用

    statickeyword主要有两种作用:第一,仅仅想为某特定数据类型或对象分配单一的存储空间,而与创建对象的个数无关.第二,希望某个方法或属性与类而不是对象关联在一起,也就是说,在不创建对象的情况下 ...

  6. [javase学习笔记]-8.5 statickeyword的使用场景

    这一节我们来看一下在我们开发的过程中,在什么时候我们要用到statickeyword进行静态修饰. 我们这里所说的静态.无非就是两种.一种是静态变量,一种是静态函数,我们分这两种情况进行说明stati ...

  7. 【C语言天天练(二)】statickeyword

    引言:                 statickeyword不仅能够修饰变量.并且能够修饰函数.了解它的使用方法,不仅对阅读别人的代码有帮助,也有助于自己写出更加健壮的程序. 使用方法:     ...

  8. 一起talk C栗子吧(第一百二十六回:C语言实例--statickeyword)

    各位看官们,大家好,上一回中咱们说的内置宏的样例.这一回咱们说的样例是:static关键字. 闲话休提.言归正转. 让我们一起talk C栗子吧! 看官们,C语言提供了static关键字.它常常出如今 ...

  9. statickeyword

    static词义:静态的,可以用于修饰变量和方法,static方法块可以优先于构造函数运行. 被static修饰的变量,叫静态变量,静态变量在内存中仅仅有一份拷贝 public static Stri ...

随机推荐

  1. node-sass的安装问题

    1.认识node-sass 我觉得要解决node-sass的问题,你首先至少要简单的了解node-sass是个什么东西?为什么要安装它? 对于在项目中使用sass的语法的时候,需要通过sass-loa ...

  2. (十三)RabbitMQ消息队列-VirtualHost与权限管理

    原文:(十三)RabbitMQ消息队列-VirtualHost与权限管理 VirtualHost 像mysql有数据库的概念并且可以指定用户对库和表等操作的权限.那RabbitMQ呢?RabbitMQ ...

  3. php 模拟get提交

    方法一: $re = file_get_contents($url); print_r($re); 方法二: $ch = curl_init("http://www.jb51.net/&qu ...

  4. zTree异步加载(自定义图片)

    原文链接:https://blog.csdn.net/qq_37936542/article/details/78429675 zTree官网:点击打开链接 一:文件下载 点击首页右下角的ztree ...

  5. [Angular] NgRx/effect, why to use it?

    See the current implementaion of code, we have a smart component, and inside the smart component we ...

  6. 在nginx中使用lua直接訪问mysql和memcaced达到数据接口的统一

    安装nginx參见<nginx+lua+redis构建高并发应用> 让nginx 中的nginx_lua_module支持mysql 和memcache 下载 https://github ...

  7. Windows 查看硬盘ID(diskpart命令)

    使用diskpart命令Win+R键运行cmd,进入命令行界面:1.diskpart2.list disk 查看有几块硬盘3.select disk 0 选择第一块硬盘4.detail disk 显示 ...

  8. 数据结构与算法——常用数据结构及其Java实现

    前言 仿佛一下子,2017年就快过去一半了,研一马上就要成为过去式了,我打算抓住研一的尾巴,好好梳理一下数据结构与算法,毕竟这些基础知识是很重要的嘛.所以准备在这里搞一个系列的文章,以期透彻. 本系列 ...

  9. html5中的dom中的各种节点的层次关系是怎样的

    html5中的dom中的各种节点的层次关系是怎样的 一.总结 一句话总结:Node节点是所有节点的基类,所以都继承它的方法 1.dom提供在js中动态修改html标签的作用 比如增加修改标签等,并且是 ...

  10. BZOJ 2096 Pilots - 单调队列STL(deque)

    传送门 分析: 单调队列:维护两个递增.递减的队列,每次都加入新元素并更新,如果最大值(递减队首)-最小值(递增队首) > k,那么将最左段更新为前面两者中较前的那一个,并弹掉.用deque可以 ...