【简介】

1.静态数据成员在类中声明,在源文件中定义并初始化;

2.静态成员函数没有this指针,只能访问静态数据成员;

3.调用静态成员函数:(1)对象、(2)直接调用;

4.静态成员函数的地址可用普通函数指针储存,可作为回调函数的参数。

1.静态数据成员

1.静态数据成员与全局变量一样都是静态分配存储空间的,在编译时,就要为类的静态数据成员分配存储空间。但全局变量在程序中的任何位置都可以访问它,而静态数据成员受到访问权限的约束。必须是public权限时,才可能在类外进行访问。

2.静态数据成员的初始化

(1)*静态数据成员初始化是在类的文件(.cpp),而不是在类的头文件(.h)中进行的。这是因为类声明位于头文件中,程序可能将头文件包括在其他几个文件中。如果在头文件中进行初始化,将出现多个初始化语句副本,从而引发错误。

A.h文件
class A
{
  private:
  static int a;
}; A.cpp文件
int A::a = ; //数据类型 类名::静态数据成员名 = 初值。

(2)因为静态成员属于整个类,而不属于某个对象,如果在类内初始化,会导致每个对象都包含该静态成员。

(3)静态成员变量在类中仅仅是声明(声明只是表明了变量的数据类型和属性,并不分配内存),没有定义,所以要在类的外面定义(定义给静态成员变量分配内存)。

class A
{
public:
static int a; //声明但未定义
}; int main()
{
  printf("%d", A::a); //error。 a没分配内存,不能访问。
  return ;
} class A
{
  public:
  static int a; //声明但未定义
}; int A::a = ; //定义了静态成员变量,同时初始化。也可以写"int A:a;",即不给初值,同样可以通过编译。 int main()
{
  printf("%d", A::a);//ok。a分配了内存,可以访问。
  return ;
}

  

(4)注意:静态数据成员在类声明中声明,在包含类方法的文件中初始化。

3.静态成员能在类的范围内共享。在类中,静态成员可以实现多个对象之间的数据共享。它的值是可以更新的。只要对静态数据成员的值更新一次,保证所有对象存取更新后的相同的值。

4.类的静态成员是可以独立访问的,也就是说,不需要创建类的实例就可以访问静态成员。

5.派生类对象与基类对象共享基类静态数据成员

class base
{
public:
static int _num; //声明静态成员
}; int base::_num = ; //静态数据成员的真正定义 class derived : public base
{
}; main()
{
base a;
derived b;
a._num++;
cout << a._num << endl;
b._num++;
cout << b._num << endl;
cout << a._num << endl;
}
运行结果:

6.静态数据成员的类型可以是所属类的类型,而普通数据成员则不可以。普通数据成员的只能声明为所属类类型的指针或引用。

class base
{
public:
static base a;//正确,静态数据成员
base b;//错误
base *p;//正确,指针
base &m;//正确,引用
};

7.静态数据成员的值const成员函数可以被合法的改变

base.h文件
class base
{
public:
base() { i = ; }
private:
static int a;
int i;
void test() const //const 成员函数
{
a++;//正确,static数据成员
i++;//错误
}
}; base.cpp文件
int base::a = ;

2.静态成员函数

1.静态函数是使用 static 修饰符修饰的函数,静态函数没有 this 指针,只能访问静态成员

2.调用静态成员函数(只能访问静态成员)

(1)对象可调用静态成员函数

(2)可直接调用静态成员函数

class Obj
{
static int i;
public:
Obj() { i++; cout << ’a’; }
~Obj() { i--; cout << ’b’; }
static int getVal() { return i; } //静态成员函数(只能访问静态成员)
}; int Obj::i = ; //静态成员初始化 void f() { Obj ob2; cout << ob2.getVal(); } //1.对象可调用静态成员函数 void main()
{
Obj ob1;
f();
Obj *ob3 = new Obj; //new新建一个对象,再将该对象的指针赋值给指针ob3
cout << ob3->getVal();
delete ob3;
cout << Obj::getVal(); //2.可直接调用静态成员函数 输出:aa2ba2b1b
}

3.在类中如果函数调用的结果不会访问或者修改任何对象数据成员,这样的成员声明为静态成员函数比较好。

4.类的静态成员函数可以访问类的私有成员,但是静态成员函数只能直接访问类的静态私有成员,因为静态成员函数是不可以直接访问非静态的成员的。

5.静态成员函数可以借助对象名指针访问类的非静态私有成员

class DATA
{
private:
int i; //非静态私有成员
static int j; //静态数据成员
public:
DATA(int num) { i = num; j += num; }
static show(DATA c)
{
cout << ”i = ” << c.i << ”, j = ” << j << endl; //非静态成员i(用对象名来引用);静态成员(直接引用)。
}
}; int DATA::j = ; void main()
{
DATA a(), b();
DATA::show(a);
DATA::show(b);
}
输出:
i = , j =
i = , j =

6.不能把静态成员函数定义为虚函数。静态成员函数也是在编译时分配存储空间,所以在程序的执行过程中不能提供多态性。

7.*静态成员函数的地址可用普通函数指针储存,而普通成员函数地址需要用类成员函数指针来储存。

base.h文件
class base
{
public:
static int func1();
int func2();
}; base.cpp文件
main()
{
int(*pf1)() = &base::func1;
int (base::*pf2)() = &base::func2;
}

真实案例:

DDPlatform.h文件

/*
登陆状态回调
ulState: 当前登陆状态
ulUserHandle: 登陆成功后的用户句柄,ucState==LOGIN_SUCCEED时值有效
ulALCHandle: 报警服务器句柄,ucState==LOGIN_SUCCEED时值有效
*/
typedef void (CALLBACK *fLoginStateCallback)(ULONG ulState, ULONG ulUserHandle, ULONG ulALCHandle); /*
设备状态改变回调
ulCameraID: 设备ID
ulState: 当前状态
ulUserHandle: 登陆用户句柄
ulALCHandle: 报警服务器句柄
*/
typedef void (CALLBACK *fCameraRestateCallback)(ULONG ulCameraID, ULONG ulState, ULONG ulUserHandle, ULONG ulALCHandle); struct PE_REGCALLBACK
{
fLoginStateCallback cbLoginState;
fCameraRestateCallback cbCameraRestate;
}; AlarmSystemWindow.h文件
#pragma once #include "DDPlatform.h"
#include <BaseWidget.h> class AlarmSystemWindow : public BaseWidget
{
Q_OBJECT public:
AlarmSystemWindow(QWidget *parent);
~AlarmSystemWindow(); public:
static void CALLBACK LoginState(ULONG ulState, ULONG ulUserHandle, ULONG ulALCHandle);
static void CALLBACK CameraRestate(ULONG ulCameraID, ULONG ulState, ULONG ulUserHandle, ULONG ulALCHandle); private:
PE_REGCALLBACK m_cbRegister; priate:
void init();
}; AlarmSystemWindow.cpp文件 void AlarmSystemWindow::init()
{
memset(&m_cbRegister, , sizeof(m_cbRegister));
m_cbRegister.cbLoginState = LoginState; //静态成员函数的地址可用普通函数指针储存
m_cbRegister.cbCameraRestate = CameraRestate; bool RegisterCallback = DDPlatform::DDPlat_RegisterCallback(m_cbRegister);
} void CALLBACK AlarmSystemWindow::LoginState(ULONG ulState, ULONG ulUserHandle, ULONG ulALCHandle)
{
AlarmSystemWindow* pThat = (AlarmSystemWindow*)g_AlarmWindow; if (ulState == LOGIN_SUCCEED)
{
pThat->g_ulLoingUserHandle = ulUserHandle; pThat->sglSendLoginHandle(ulUserHandle); //发送登录句柄
}
else if (ulState == LOGIN_QUERERR || ulState == LOGIN_CONNERR || ulState == LOGIN_LOGINERR || ulState == LOGIN_AUTHFAIL)
{
}
} void CALLBACK AlarmSystemWindow::CameraRestate(ULONG ulCameraID, ULONG ulState, ULONG ulUserHandle, ULONG ulALCHandle)
{
AlarmSystemWindow* pThat = (AlarmSystemWindow*)g_AlarmWindow; //获取设备报警状态
if (ulState == CAMERAST_ALARMING) { //报警中 pThat->sglSendAlarmDeviceData(ulCameraID);
}
}

注意:回调函数是将一个函数的指针作为另一个函数的参数,当另一个函数执行完后再执行该函数。

博客园的这个文本编辑实在是太难搞了,就这样吧...强迫症的我也屈服了

C++基础(静态数据成员和静态成员函数)的更多相关文章

  1. C++学习5-面向对象编程基础(构造函数、转换构造、静态数据成员、静态成员函数、友元)

    知识点学习 类 const作用 C语言的const限定符的含义为"一个不能改变值的变量",C++的const限定符的含义为"一个有类型描述的常量": const ...

  2. C++ 静态数据成员和静态成员函数

    一 静态数据成员: 1.静态数据成员的定义. 静态数据成员实际上是类域中的全局变量.所以,静态数据成员的定义(初始化)不应该被放在头文件中,因为这样做会引起重复定义这样的错误.即使加上#ifndef ...

  3. C++静态数据成员与静态成员函数

    一般情况下,如果有n个同类的对象,那么每一个对象都分别有自己的数据成员,不同对象的数据成员各自有值,互不相干.但是有时人们希望有某一个或几个数据成员为所有对象所共有,这样可以实现数据共享. 可以使用全 ...

  4. C++中static修饰的静态成员函数、静态数据成员

    1.静态成员函数.静态数据成员 在类中,用static修饰的成员函数被称为静态成员函数,而用static修饰的数据成员就称为静态数据成员:与普通的成员函数和数据成员不同, 静态成员函数和静态数据成员有 ...

  5. C++类静态数据成员与类静态成员函数

    from:://http://blog.csdn.net/taina2008/article/details/1684834 把类中的函数都定义成静态函数,这样相当于在编译时就分配了空间,这样不需要实 ...

  6. 《挑战30天C++入门极限》C++类静态数据成员与类静态成员函数

        C++类静态数据成员与类静态成员函数 在没有讲述本章内容之前如果我们想要在一个范围内共享某一个数据,那么我们会设立全局对象,但面向对象的程序是由对象构成的,我们如何才能在类范围内共享数据呢? ...

  7. 转:C语言中的static变量和C++静态数据成员(static member)

    转自:C语言中的static变量和C++静态数据成员(static member) C语言中static的变量:1).static局部变量        a.静态局部变量在函数内定义,生存期为整个程序 ...

  8. C++中静态数据成员

    类的静态成员不能由类的构造函数来初始化.因为即使不存在类的任何对象时,类的静态成员依然存在并且可以被使用.类的静态成员也不能访问任何类的非静态成员. 类名和类对象都可以直接调用静态数据成员.因为静态数 ...

  9. 一个类的实例化对象所占空间的大小(对象大小= vptr(可能不止一个) + 所有非静态数据成员大小 + Aligin字节大小(依赖于不同的编译器))

    注意不要说类的大小,是类的对象的大小. 首先,类的大小是什么?确切的说,类只是一个类型定义,它是没有大小可言的. 用sizeof运算符对一个类型名操作,得到的是具有该类型实体的大小. 如果 Class ...

随机推荐

  1. docker run 参数含义

    -a stdin: 指定标准输入输出内容类型,可选 STDIN/STDOUT/STDERR 三项: -d: 后台运行容器,并返回容器ID: -i: 以交互模式运行容器,通常与 -t 同时使用:     ...

  2. Spring boot 去除URL 里的 JSESSIONID

    方法一 application.yml 里设置 server: port: 80 servlet: session: tracking-modes: cookie cookie: http-only: ...

  3. python中whl的讲解

    whl 格式:这是一个压缩包,在其中包含了py文件,以及经过编译的pyd文件. 这个格式可以使文件在不具备编译环境的情况下,选择合适自己的python环境进行安装. 安装方法如下 进入命令行输入:pi ...

  4. 判断一个数组的长度用 Length 还是 SizeOf ?

    最近发现一些代码, 甚至有一些专家代码, 在遍历数组时所用的数组长度竟然是 SizeOf(arr); 这不合适! 如果是一维数组.且元素大小是一个字节, 这样用看不出错误, 譬如: var   arr ...

  5. 移动端IM系统的协议选型:UDP还是TCP?(转)

    源: 移动端IM系统的协议选型:UDP还是TCP?

  6. Java基础 println 输出常量的示例

        JDK :OpenJDK-11      OS :CentOS 7.6.1810      IDE :Eclipse 2019‑03 typesetting :Markdown   code ...

  7. flutter Switch组件 On/off 用于切换一个单一状态

    import 'package:flutter/material.dart'; class SwitchDemo extends StatefulWidget { @override _SwitchD ...

  8. centos7.6_x86_64使用Squid搭建代理服务器让windows上网

    centos7.6_x86_64使用Squid搭建代理服务器让windows上网 windows机器很多站点访问受限,可以在没有限制外网的机器上面搭建代理服务器,其它电脑可以配置代理通过这台不受限制的 ...

  9. 0.9.0.RELEASE版本的spring cloud alibaba sentinel限流、降级处理实例

    先看服务提供方的,我们在原来的sentinel实例(参见0.9.0.RELEASE版本的spring cloud alibaba sentinel实例)上加上限流.降级处理,三板斧只需在最后那一斧co ...

  10. DataGrip 2019.1 连接mysql 8.0.16

    # 下载mysql Connector/J驱动包 https://dev.mysql.com/downloads/connector/j/ 然后解压到一个目录 # 新建mysql 8.0连接驱动 打开 ...