引言

有时候需要类的一些成员与类本身相关联,而不是与类的每个对象相关联。比如类的所有对象都要共享的变量,这个时候我们就要用到类的静态成员

声明类的静态成员

声明静态成员的方法是使用static关键字。

static成员可以是public也可以是private的。

例如,定义一个类表示银行的账户记录:

class Account{
public:
//其他非静态函数及数据成员
//静态函数
static double get_rate(){ return interestRate; }
static void set_rate(double r){ interestRate = r; }
private:
static double interestRate;//该类的所有对象公用同一个利率
//其他static private函数
//其他非static 函数及数据成员
};

Note:

  • 类的静态成员存在于任何对象之外,对象中不包含任何与静态数据成员有关的数据。
  • 静态成员函数不与任何对象绑定到一起,不能在静态成员函数中使用this指针。静态成员函数不能被声明为const。

使用类的静态成员

使用作用域运算符::直接访问静态成员。

double r;
r = Account::get_rate();

虽然静态成员不属于类的任何对象,但仍然可以通过类的对象访问静态成员。

Account ac1;
Account *ac2 = &ac1;
double r = ac1.get_rate();
r = ac2->get_rate();

成员函数可以直接使用静态成员,不需要作用域运算符。

定义静态成员

定义静态成员函数

类的静态成员函数既可以定义在类的外部也可以定义在类的内部(注意定义和声明的区别)。

当在类的外部定义静态成员函数时,不能使用static关键字,static关键字只在类内部该静态成员函数的声明处使用。否则重复。

当在类的外部定义静态成员函数时,必须指明该函数所属的类,如:

class Account{
public:
//其他非静态函数及数据成员
//静态成员函数
static double get_rate(){ return interestRate; }
static void set_rate(double r){ interestRate = r; }
static void print();//静态成员函数声明
private:
static double interestRate;//该类的所有对象公用同一个利率
//其他static private函数
//其他非static 函数及数据成员
};
//定义静态函数时不需要使用static关键字,否则重复。另外指明该函数所属的类。
void Account::print(){
//要完成的工作
}

定义静态数据成员

因为静态数据成员不属于类的任何一个对象,所以他们并不是在创建类的对象的时候被定义的。不能在类的内部初始化静态数据成员,必须在类的外部定义和初始化每个静态数据成员。

double Account::interestRate = initRate();//不用static关键字

静态数据成员的类内初始化

前面提到,类的静态数据成员不应该在类的内部被初始化。但若静态数据成员同时还是constexpr类型,则可以在类内初始化。

即使一个常量静态成员在类内被初始化了,通常也应该在类的外部定义一下该成员,但类外定义使不能再指定初始值,因为在类内已经提供了初始值。

静态数据成员的特殊应用场景

  1. 静态成员独立于任何对象,因此,静态数据成员的类型可以是他所属的类类型,非静态数据成员只能声明为他所属的类的指针或引用。

    例如:
class Person{
public:
//...
private:
static Person p; //正确,静态数据成员可以是不完全类型
Person *p1; //正确:指针成员和引用可以是不完全类型
Person &p2 //正确
Person p3; //错误:数据成员必须是完全类型。
};//在此之前,class Person之后,Person类都是不完全类型,因只声明完但还没有定义完
  1. 可以使用静态成员作为默认实参
class Screen{
public:
Screen& clear(char = bkground);
private:
static const char bkground;
}

非静态数据成员不能作为默认实参,因为非静态数据成员属于对象,对象的值是在运行时确定的,但默认参数却是在编译时确定的,也就是说,默认参数确定时还没有真正的对象被创建,因此不能用非静态数据成员作为默认参数,否则引发错误。


声明:

c++ Basic是对《C++ Primer 第五版》的个人总结与疑难解释。

如果想要深入了解更多,请支持正版。

c++中的静态成员的更多相关文章

  1. 编写高质量代码改善C#程序的157个建议[优先考虑泛型、避免在泛型中声明静态成员、为泛型参数设定约束]

    前言 泛型并不是C#语言一开始就带有的特性,而是在FCL2.0之后实现的新功能.基于泛型,我们得以将类型参数化,以便更大范围地进行代码复用.同时,它减少了泛型类及泛型方法中的转型,确保了类型安全.委托 ...

  2. C++类中的静态成员变量与静态成员函数

    最近一直看c++相关的项目,但总是会被c++类中的静态成员变量与静态成员函数的理解感觉很是模糊,不明白为什么类中要是用静态成员变量.于是在网上搜集了一些资料,自己再稍微总结下. 静态成员的概念: 静态 ...

  3. C#中的静态成员和非静态成员

    C#的类中可以包含两种方法:C#静态方法与非静态方法.那么他们的定义有什么不同呢?他们在使用上会有什么不同呢? 让我们来看看最直观的差别:使用了static 修饰符的方法为静态方法,反之则是非静态方法 ...

  4. JAVA中的静态成员

    //Java中的静态成员 /* *静态的成员变量是属于类的,不属于某个对象,是共享的. * 访问时可以用类名.静态属性直接访问,也可以用对象.访问,后者不提倡. * 静态的成员方法只能访问静态的成员 ...

  5. C++类中的静态成员变量和静态成员函数的作用

    数据成员可以分为静态变量.非静态变量两种. 静态成员:静态类中的成员加入static 修饰符,即是静态成员,可以使用类名+静态成员名访问此静态成员,因为静态成员存在于内存,非静态成员需要实例化才会分配 ...

  6. C++ 类中的静态成员变量,静态成员函数

    //类中的静态成员变量,静态成员函数 #define _CRT_SECURE_NO_WARNINGS #include<iostream> using namespace std; /* ...

  7. 编写高质量代码改善C#程序的157个建议——建议33:避免在泛型类型中声明静态成员

    建议33:避免在泛型类型中声明静态成员 在上一建议中,已经理解了应该将MyList<int>和MyList<string>视作两个完全不同的类型,所以,不应该将MyList&l ...

  8. C++ 中的静态成员函数与静态成员变量

    于CSDN 2014-01-17 与静态数据成员一样,静态成员函数是类的一部分,而不是对象的一部分.如果要在类外调用公用的静态成员函数,要用类名和域运算符"∷".如Box∷volu ...

  9. c++类中的静态成员

    静态成员和非静态成员的区别: 类静态成员用static修饰,类的静态成员属于类本身,而不属于类的某个具体对象,静态成员被类的所有对象共享,因此某个对象对静态成员(数据成员)的修改对其对象是可见的.而类 ...

  10. C++类中的静态成员变量与静态成员函数的使用

    代码: #include <iostream> #include <string> #include <cstdio> using namespace std; c ...

随机推荐

  1. Sql server 多列去重复值,相同的只显示一条数据

    CREATE TABLE #tp( headerNo VARCHAR(10), machineNO VARCHAR(10), descrption nVARCHAR(20), artNo VARCHA ...

  2. 多边形游戏——区间dp

    题目描述 多边形(Polygon)游戏是单人玩的游戏,开始的时候给定一个由N个顶点构成的多边形(图1所示的例子中,N=4),每个顶点被赋予一个整数值,而每条边则被赋予一个符号:+(加法运算)或者*(乘 ...

  3. 人脸真伪验证与识别:ICCV2019论文解析

    人脸真伪验证与识别:ICCV2019论文解析 Face Forensics++: Learning to Detect Manipulated Facial Images 论文链接: http://o ...

  4. TinyML设备设计的Arm内核

    TinyML设备设计的Arm内核 Arm cores designed for TinyML devices Arm推出了两个新的IP核,旨在为终端设备.物联网设备和其低功耗.成本敏感的应用程序提供机 ...

  5. windows 设置nginx开机自启动

    将Nginx设置为Windows服务 需要借助"Windows Service Wrapper"小工具,项目地址: https://github.com/kohsuke/winsw ...

  6. ES6中的数组方法扩展

    上一篇文章小编简单介绍了在ES6中,一些常用的方法和一些简单的应用,在这篇文章中,小编将针对ES6中数组常用方法进行扩展,相信经过这篇文章之后,每一位小伙伴下班时间会有所提前,就算从原来的996变成9 ...

  7. 「题解」agc031_e Snuke the Phantom Thief

    本文将同步发布于: 洛谷博客: csdn: 博客园: 简书. 题目 题目链接:洛谷 AT4695.AtCoder agc031_e. 题意简述 在二维平面上,有 \(n\) 颗珠宝,第 \(i\) 颗 ...

  8. 【NX二次开发】获取用户输入的字符串uc1603

    效果: 源码: extern DllExport void ufsta(char *param, int *returnCode, int rlen) { UF_initialize(); strin ...

  9. 关于kubernetes的十七个实验(一)

    实验综述 Kubernetes用来管理云平台上的容器化应用,这里从 https://www.katacoda.com/courses/kubernetes 学习Kubernetes的使用,对Kuber ...

  10. NXNSAttack漏洞简析

    漏洞简介: 该漏洞为DNS 放大攻击,是 DDoS 攻击,攻击者利用 DNS 服务器中的漏洞将小查询转换为可能破坏目标服务器的更大负载. 在 NXNSAttack 的情况下,远程攻击者可以通过向易受攻 ...