C++ 中间statickeyword

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

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

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

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

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

正文段

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. 派生类是基类的组合

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

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

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

时间: 2024-12-13 17:28:51

C++ 中间statickeyword的相关文章

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

statickeyword主要有两种作用:第一,仅仅想为某特定数据类型或对象分配单一的存储空间,而与创建对象的个数无关.第二,希望某个方法或属性与类而不是对象关联在一起,也就是说,在不创建对象的情况下就能够通过类来直接调用方法或使用类的属性.详细而言.static在Java语言中主要有四种使用情况:成员变量.成员方法.代码块.内部类. (1)static成员变量 尽管Java语言中没有全局的概念,但能够通过statickeyword来达到全局的效果.Java类提供了两种类型的变量:用static

statickeyword于C和C++用法

一.C语言statickeyword两个使用 1).一个功能修改内部使用的变量,函数内的静态变量.这些变量的寿命比功能不再,它是具有一定的函数"状态",使用静态变量的作用通常是不可重入.也不是线程安全的,实例strtok() 2)使用文件级(体外),修饰变量或函数,变量该变量或函数仅仅能在文本可见,其它文件看不到,也訪问不到该变量或函数. 二.C++语言的statickeyword的四种使用方法 因为C++引入了class,在保持与C语言兼容的同一时候.statickeyword又有了

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

这一节我们来学习java语言中一个新的keyword就是statickeyword. 当然对于每个keyword,我们都要明白的是它有什么作用,怎么用.我们先来看一个样例: class Person { String name;//姓名 String country = "中国";//国籍 public void printInfo() { System.out.println(name+":"+country); } } class StaticTest { pu

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

引言:                 statickeyword不仅能够修饰变量.并且能够修饰函数.了解它的使用方法,不仅对阅读别人的代码有帮助,也有助于自己写出更加健壮的程序. 使用方法:                 用于不同的上下文环境时,statickeyword具有不同的意义.       (一)         当它用于函数定义时,或用于代码块之外的变量声明时,statickeyword用于改动标示符的链接属性,从externl改为internal.但标示符的存储类型和作用域不受

Java中的statickeyword具体解释

1.statickeyword主要有2个作用: ①为某特定的数据类型或者对象分配单一的存储空间.而与创建对象的个数无关. ②在不创建对象的情况下能够直接通过类名来直接调用方法或者使用类的属性. 2.static主要有4种使用情况:成员变量(属性),成员方法.代码块,和内部类 3.Java中没有全局变量的概念.可是能够通过static来实现全局变量的效果. Java中提供了2种类型的变量:①用static修饰的静态变量②实例变量 他们的差别是静态变量时属于类的,仅仅要静态变量所在的类被载入.就会被

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

这一节我们来看一下在我们开发的过程中,在什么时候我们要用到statickeyword进行静态修饰. 我们这里所说的静态.无非就是两种.一种是静态变量,一种是静态函数,我们分这两种情况进行说明statickeyword的使用场合. 一.静态变量 我们在7.8节中对statickeyword特点和7.9节中成员变量与静态变量差别进行学习的时候就已经非常明白的指出了静态变量是共享数据,而对象中封装的特有数据. 因此我们能够这样解释:当分析对象中所具备成员变量的值是同样的.且不须要对象做改动,这时这个成

java中statickeyword

1.static变量 依照是否静态的对类成员变量进行分类可分两种:一种是被static修饰的变量,叫静态变量或类变量:还有一种是没有被static修饰的变量,叫实例变量. 两者的差别是: 对于静态变量在内存中仅仅有一个拷贝(节省内存),jvm仅仅为静态分配一次内存,在载入类的过程中完毕静态变量的内存分配.可用类名直接訪问(方便).当然也能够通过对象来訪问(可是这是不推荐的). 对于实例变量,没创建一个实例.就会为实例变量分配一次内存,实例变量能够在内存中有多个拷贝,互不影响(灵活). 所以一般在

AMFPHP1.4与PHP5.3及以上版本号不兼容问题的解决

近期在升级PHP5.4版本号,AMFPHP出现了兼容性问题.解决过程记录例如以下. 1.ereg类相关函数改动为preg相关函数. 2.通过错误日志输出的提示.将全部以静态方式调用的类函数加入statickeyword. 3.改动PHP配置文件.给data.timezone加入默认时区. 尽量使错误输出到日志,通常是些不兼容性问题.假设错误日志没输出能够使用Charles Proxy类的软件来查看HTTP传输的内容. NetConnection.Call.BadVersion问题的产生主要是传输

面向对象基础——构造方法私有化、对象数组、内部类

构造方法私有化 类的封装性不光体如今对属性的封装上.实际上方法也是能够被封装的,当然,在方法封装上也包括了对构造方法的封装.比如例如以下代码就是对构造方法封装. class Singleton{ private Singleton(){ // 将构造方法进行了封装,私有化 } public void print(){ System.out.println("Hello World!!!") ; } }; 使用 class Singleton{ private Singleton(){