C++类静态成员与类静态成员函数详解

当将类的某个数据成员声明为static时,该静态数据成员只能被定义一次,而且要被同类的所有对象共享。各个对象都拥有类中每一个普通数据成员的副本,但静态数据成员只有一个实例存在,与定义了多少类对象无关。静态方法就是与该类相关的,是类的一种行为,而不是与该类的实例对象相关。

静态数据成员的用途之一是统计有多少个对象实际存在。

静态数据成员不能在类中初始化,实际上类定义只是在描述对象的蓝图,在其中指定初值是不允许的。也不能在类的构造函数中初始化该成员,因为静态数据成员为类的各个对象共享,否则每次创建一个类的对象则静态数据成员都要被重新初始化。

静态成员不可在类体内进行赋值,因为它是被所有该类的对象所共享的。你在一个对象里给它赋值,其他对象里的该成员也会发生变化。为了避免混乱,所以不可在类体内进行赋值。

静态成员的值对所有的对象是一样的。静态成员可以被初始化,但只能在类体外进行初始化。

一般形式:
数据类型类名::静态数据成员名=初值
注意:不能用参数初始化表对静态成员初始化。一般系统缺省初始为0。

静态成员是类所有的对象的共享的成员,而不是某个对象的成员。它在对象中不占用存储空间,这个属性为整个类所共有,不属于任何一个具体对象。所以静态成员不能在类的内部初始化,比如声明一个学生类,其中一个成员为学生总数,则这个变量就应当声明为静态变量,应该根据实际需求来设置成员变量。


代码如下:

#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指针,它不能返回非静态成员,因为除了对象会调用它外,类本身也可以调用。

静态成员函数可以直接访问该类的静态数据和函数成员,而访问非静态数据成员必须通过参数传递的方式得到一个对象名,然后通过对象名来访问。


代码如下:

class Myclass
{
private:
        int a,b,c;
        static int Sum;    //声明静态数据成员
public:
        Myclass(int a,int b,int c);
        void GetSum();
};
int Myclass::Sum=0;       //定义并初始化静态数据成员
Myclass::Myclass(int a,int b,int c)
{
        this->a=a;
        this->b=b;
        this->c=c;
        Sum+=a+b+c;
}
void Myclass::GetSum()
{
        cout <<"Sum=" <<Sum <<endl;
}
int main(void)
{
        Myclass me(10,20,30);
        me.GetSum();
        system("pause");
        return 0;
}

由上例可知,非静态成员函数可以任意地访问静态成员函数和静态数据成员。
非静态成员函数Myclass(int a,int b,int c)和GetSum()都访问了静态数据成员Sum。
静态成员函数不能访问非静态成员函数和非静态数据成员。

关于静态成员函数,可以总结为以下几点:

出现在类体外的函数定义不能指定关键字static;

静态成员之间可以相互访问,包括静态成员函数访问静态数据成员和访问静态成员函数;

非静态成员函数可以任意地访问静态成员函数和静态数据成员;

静态成员函数不能访问非静态成员函数和非静态数据成员;

由于没有this指针的额外开销,因此静态成员函数与类的全局函数相比速度上会有少许的增长;

调用静态成员函数,可以用成员访问操作符(.)和(->)为一个类的对象或指向类对象的指针调用静态成员函数,当同一类的所有对象使用一个量时,对于这个共用的量,可以用静态数据成员变量,这个变量对于同一类的所有的对象都取相同的值。静态成员变量只能被静态成员函数调用。静态成员函数也是由同一类中的所有对象共用。只能调用静态成员变量和静态成员函数。

(0)

相关推荐

  • 深入C++ string.find()函数的用法总结

    #include <string>#include <iostream>using namespace std; void main(){ 复制代码 代码如下: ////find函数返回类型 size_typestring s("1a2b3c4d5e6f7g8h9i1a2b3c4d5e6f7g8ha9i");string flag;string::size_type position;//find 函数 返回jk 在s 中的下标位置 position = s.f

  • 浅析C/C++中sort函数的用法

    sort是STL中提供的算法,头文件为#include<algorithm>以及using namespace std; 函数原型如下: template <class RandomAccessIterator> void sort ( RandomAccessIterator first, RandomAccessIterator last ); template <class RandomAccessIterator, class Compare> void sor

  • C++中的friend友元函数详细解析

    友元函数是可以直接访问类的私有成员的非成员函数.它是定义在类外的普通函数,它不属于任何类,但需要在类的定义中加以声明,声明时只需在友元的名称前加上关键字friend. 我们已知道类具有封装和信息隐藏的特性.只有类的成员函数才能访问类的私有成员,程序中的其他函数是无法访问私有成员的.非成员函数可以访问类中的公有成员,但是如果将数据成员都定义为公有的,这又破坏了隐藏的特性.另外,应该看到在某些情况下,特别是在对某些成员函数多次调用时,由于参数传递,类型检查和安全性检查等都需要时间开销,而影响程序的运

  • C++中的哈希容器unordered_map使用示例

    随着C++0x标准的确立,C++的标准库中也终于有了hash table这个东西. 很久以来,STL中都只提供<map>作为存放对应关系的容器,内部通常用红黑树实现,据说原因是二叉平衡树(如红黑树)的各种操作,插入.删除.查找等,都是稳定的时间复杂度,即O(log n):但是对于hash表来说,由于无法避免re-hash所带来的性能问题,即使大多数情况下hash表的性能非常好,但是re-hash所带来的不稳定性在当时是不能容忍的. 不过由于hash表的性能优势,它的使用面还是很广的,于是第三方

  • C++ 二维数组参数传递的实现方法

    C++ 二维数组参数传递的实现方法 int a[2][2]={ {4, 6}, {9, 11} }; 我定义了这样一个数组,我想把这个数组作为参数,传递到一个函数中,并要在函数中能引用该二维数组的元素,我该怎么做? 第一种方式是直接传递二维数组,但是必须标明第二维的值,因为如果只是传递a[][],编译器无法分配这样的数组,所以要这样传int a[][3] 第二种方法是传递指针数组方式,即int (*a)[3] 第三种是传递指针方法. 具体实施见代码: 方法1:传递数组,注意第二维必须标明 //二

  • C++运算符重载的方法详细解析

    运算符重载实质上是函数的重载 重载运算符的函数一般格式如下: 函数类型    operator  运算符名称    (形参表列) {对运算符的重载处理} 例如,想将"+"用于Complex(复数)的加法运算,函数的原型可以是这样的: 复制代码 代码如下: Complex operator + (Complex & c1,Complex &c2); 其中,operator是关键字,时候专门用于定义重载运算符的函数的,运算符名称就是C++提供给用户的预定运算符. 注意:函数

  • C++类与对象深入之静态成员与友元及内部类详解

    目录 一:静态成员 1.1:静态成员分类 1.2:静态成员变量 1.3:静态成员函数 1.4:总结特性 1.5:试题示例 1.6:C++11成员初始化新玩法 二:友元 2.1:全局函数做友元 2.2:类做友元 2.3:成员函数做友元 三:内部类 3.1:概念 3.2:特性 一:静态成员 静态成员就是在成员变量和成员函数前加上关键字static,称为静态成员.C++里面尽量用静态成员变量代替全局变量. 1.1:静态成员分类 1️静态成员变量: 所有对象共享同一份数据 在编译阶段分配内存 类内声明,

  • C++类中六个默认的成员函数详解

    浅谈 先来说一下"this指针": C++中通过引入this指针解决该问题,暨:C++编译器给每个"非静态的成员函数"增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有成员变量的操作,都是通过该指针去访问,只不过所有的操作对用户是透明的,暨用户不需要来传递,编译器自动完成. 说了这么多其实编译器在生成程序时获取对象首地址的信息.然后将获取的对象的首地址存放在了寄存器中,成员函数的其它参数都是存放在栈中.而this指针参数则是

  • 浅谈C++ 类的实例中 内存分配详解

    一个类,有成员变量:静态与非静态之分:而成员函数有三种:静态的.非静态的.虚的. 那么这些个东西在内存中到底是如何分配的呢? 以一个例子来说明: #include"iostream.h" class CObject { public: static int a; CObject(); ~CObject(); void Fun(); private: int m_count; int m_index; }; VoidCObject::Fun(){ cout<<"Fu

  • C++ 类的继承与派生实例详解

     C++ 类的继承与派生实例详解 继承性是面向对象程序设计最重要的特性之一,使软件有了可重用性,C++提供的类的继承机制. 继承与派生的概念 一个新类从已有的类那里获得已有的特性,这种现象称为类的继承.同样也可以说成已有的类派生出来了新的类.类A继承自类B也就是类B派生了类A.所以继承和派生的关系就像小学时把字句和被字句的造句一样.有了继承与派生后,就有了父类/基类与子类/派生类,C++中将类B称为父类/基类,将类A称为子类/派生类. 派生类的声明: #include <iostream> u

  • Python类的继承和多态代码详解

    Python类的继承 在OOP(ObjectOrientedProgramming)程序设计中,当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类.父类或超类(Baseclass.Superclass). 我们先来定义一个classPerson,表示人,定义属性变量name及sex(姓名和性别): 定义一个方法print_title():当sex是male时,printman:当sex是female时,prin

  • Python类中的装饰器在当前类中的声明与调用详解

    我的Python环境:3.7 在Python类里声明一个装饰器,并在这个类里调用这个装饰器. 代码如下: class Test(): xx = False def __init__(self): pass def test(func): def wrapper(self, *args, **kwargs): print(self.xx) return func(self, *args, **kwargs) return wrapper @test def test_a(self,a,b): pr

  • Js类的构建与继承案例详解

    JS里类的定义和继承实在五花八门,所以单独开一个笔记本记录. 定义 派生于Object的方式 1.new Object:在创建对象后动态定义属性.方法 var Car = new Object; Car.color = "red"; Car.showColor = function(){ console.log(this.color); } //想要继承就要先构造空对象然后用__proto__原型链来继承 var Car1 = new Object; //或者 = {} Car1.__

  • sun unsafe类功能及使用注意事项详解

    目录 Unsafe简介 获取Unsafe实例 Unsafe功能列表 Unsafe的数组操作 base offset含义 index scale含义 array copy to direct memory copyMemory(Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes) Benchmark 什么时候用Unsafe Unsafe简介 Unsafe是位于sun.misc包下的一个类,主要提供

  • MySQL中Decimal类型和Float Double的区别(详解)

    MySQL中存在float,double等非标准数据类型,也有decimal这种标准数据类型. 其区别在于,float,double等非标准类型,在DB中保存的是近似值,而Decimal则以字符串的形式保存数值. float,double类型是可以存浮点数(即小数类型),但是float有个坏处,当你给定的数据是整数的时候,那么它就以整数给你处理.这样我们在存取货币值的时候自然遇到问题,我的default值为:0.00而实际存储是0,同样我存取货币为12.00,实际存储是12. 幸好mysql提供

  • C++聚合关系类的构造函数的调用顺序详解

    如图,表示一个聚合关系 下面就用简单的代码来实现 #pragma once class Engine { public: Engine(); ~Engine(); }; Engine.h #include <iostream> #include "Engine.h" using namespace std; Engine::Engine() { cout << "调用构造函数:Engine()" << endl; } Engine

随机推荐