static类成员(变量和函数)
0. 使用背景
对于特定类类型的全体对象而言,访问一个全局对象有时是必要的。
也许,在程序的任意点需要统计已创建的特定类类型对象的数量;
或者,全局对象可能是指向类的错误处理例程的一个指针;
或者,它是指向类类型对象的内在自由存储区的一个指针。
然而,全局对象会破坏封装:对象需要支持特定类抽象的实现。
如果对象是全局的,一般的用户代码就可以修改这个值。
1. static 类成员
类可以定义类 静态成员,而不是定义一个可普遍访问的全局对象。
通常,非 static 数据成员存在于类类型的每个对象中。
不像普通的数据成员,static 数据成员独立于该类的任意对象而存在;
每个 static 数据成员是与类关联的对象,并不与该类的对象相关联。
正如类可以定义共享的 static 数据成员一样,类也可以定义 static 成员函数。
static 成员函数没有 this 形参,它可以直接访问所属类的 static 成员,但不能直接使用非 static 成员。
1.1 使用类的 static 成员的优点
使用 static 成员而不是全局对象有 3 个优点:
static 成员的名字是在类的作用域中,因此可以避免与其他类的成员或全局对象名字冲突。
可以实施封装。static 成员可以是私有成员,而全局对象不可以。
通过阅读程序容易看出 static 成员是与特定类关。
1.2 定义 static 成员
在成员声明前加上关键字 static 将成员设为 static。static 成员遵循正常的公有/私有访问规则。
例如,考虑一个简单的表示银行账户的类。
每个账户具有余额和拥有者,并且按月获得利息,但应用于每个账户的利率总是相同的。
- class Account {
- public:
- // interface functions here
- void applyint() { amount += amount * interestRate; }
- static double rate() { return interestRate; }
- static void rate(double); // sets a new rate
- private:
- std::string owner;
- double amount;
- static double interestRate;
- static double initRate();
- };
这个类的每个对象具有两个数据成员:owner 和 amount。
对象没有与 static 数据成员对应的数据成员,
但是,存在一个单独的 interestRate 对象,由 Account 类型的全体对象共享。
1.3 使用类的 static 成员
可以通过作用域操作符从类直接调用 static 成员,或者通过对象、引用或指向该类类型对象的指针间接调用。
- Account ac1;
- Account *ac2 = &ac1;
- // equivalent ways to call the static member rate function
- double rate;
- rate = ac1.rate(); // through an Account object or reference
- rate = ac2->rate(); // through a pointer to an Account object
- rate = Account::rate(); // directly from the class using the scope operator
像使用其他成员一样,类成员函数可以不用作用域操作符来引用类的 static 成员:
- class Account {
- public:
- // interface functions here
- void applyint() { amount += amount * interestRate; }
- };
2. static 成员函数
Account 类有两个名为 rate 的 static 成员函数,其中一个定义在类的内部。
当我们在类的外部定义 static 成员时,无须重复指定 static 保留字,该保留字只出现在类定义体内部的声明处:
- void Account::rate(double newRate){ interestRate = newRate; }
static 成员是类的组成部分但不是任何对象的组成部分,因此,static 成员函数没有 this 指针。
通过使用非 static 成员显式或隐式地引用 this 是一个编译时错误。
因为 static 成员不是任何对象的组成部分,所以 static 成员函数不能被声明为 const。
毕竟,将成员函数声明为 const 就是承诺不会修改该函数所属的对象。
最后,static 成员函数也不能被声明为虚函数。
3. static 数据成员
static 数据成员可以声明为任意类型,可以是常量、引用、数组、类类型,等等。
static 数据成员必须在类定义体的外部定义(正好一次)。
不像普通数据成员,static 成员不是通过类构造函数进行初始化,而是应该在定义时进行初始化。
保证对象正好定义一次的最好办法,就是将 static 数据成员的定义放在包含类非内联成员函数定义的文件中。
定义 static 数据成员的方式与定义其他类成员和变量的方式相同:先指定类型名,接着是成员的完全限定名。
可以定义如下 interestRate:
- // define and initialize static class member
- double Account::interestRate = initRate();
这个语句定义名为 interestRate 的 static 对象,它是类 Account 的成员,为 double 型。
像其他成员定义一样,一旦成员名出现,static 成员的就是在类作用域中。
因此,我们可以没有限定地直接使用名为 initRate 的 static 成员函数,作为 interestRate 初始化式。
注意,尽管 initRate 是私有的,我们仍然可以使用该函数来初始化 interestRate。
像任意的其他成员定义一样,interestRate 的定义是在类的作用域中,因此可以访问该类的私有成员。
像使用任意的类成员一样,在类定义体外部引用类的 static 成员时,必须指定成员是在哪个类中定义的。
然而,static 关键字只能用于类定义体内部的声明中,定义不能标示为 static。
3.1 特殊的整型 const static 成员
一般而言,类的 static 成员,像普通数据成员一样,不能在类的定义体中初始化。
相反,static 数据成员通常在定义时才初始化。这个规则的一个例外是,
只要初始化式是一个常量表达式,整型 const static 数据成员就可以在类的定义体中进行初始化:
- class Account {
- public:
- static double rate() { return interestRate; }
- static void rate(double); // sets a new rate
- private:
- static const int period = ; // interest posted every 30 days
- double daily_tbl[period]; // ok: period is constant expression
- };
用常量值初始化的整型 const static 数据成员是一个常量表达式。
同样地,它可以用在任何需要常量表达式的地方,例如指定数组成员 daily_tbl 的维。
const static 数据成员在类的定义体中初始化时,该数据成员仍必须在类的定义体之外进行定义。
在类内部提供初始化式时,成员的定义不必再指定初始值:
- // definition of static member with no initializer;
- // the initial value is specified inside the class definition
- const int Account::period;
3.2 static 成员不是类对象的组成部分
普通成员都是给定类的每个对象的组成部分。static 成员独立于任何对象而存在,不是类类型对象的组成部分。
因为 static 数据成员不是任何对象的组成部分,所以它们的使用方式对于非 static 数据成员而言是不合法的。
- // static 数据成员的类型可以是该成员所属的类类型。
- // 非 static 成员被限定声明为其自身类对象的指针或引用:
- class Bar {
- public:
- // ...
- private:
- static Bar mem1; // ok
- Bar *mem2; // ok
- Bar mem3; // error
- };
- // 类似地,static 数据成员可用作默认实参:
- class Screen {
- public:
- // bkground refers to the static member
- // declared later in the class definition
- Screen& clear(char = bkground);
- private:
- static const char bkground = '#';
- };
非 static 数据成员不能用作默认实参,因为它的值不能独立于所属的对象而使用。
使用非 static 数据成员作默认实参,将无法提供对象以获取该成员的值,因而是错误的。
/************** 面试中常见的有关 static 类成员的问题 ****************/
Question:
什么是 static 类成员? static 成员的优点是什么? 他们与普通成员有什么不同?
Answer:
所谓 static 类成员,指的是其声明前带有关键字 static 的类成员。
static 类成员不是任意对象的组成部分,但由该类的全体对象所共享。
static 成员的优点:
static 成员的名字是在累的作用域中,因此可以避免与其他类的成员或全局对象名字冲突;
可以实施封装,static 成员可以说是私有成员,儿全局对象不可以;
通过阅读程序容易看出 static 成员是与特定类关联的,这种可见性可清晰的显示程序猿的意图。
它与普通成员的不同在于:
普通成员总是与对象相关联,是某个对象的组成部分;
而 static 成员与类相关联,由该类的全体对象所共享,不是人以对象的组成部分。
static类成员(变量和函数)的更多相关文章
- static 类成员变量 和 static const类成员变量
1.使用static类的优点: (1)避免与其他类的成员或者全局变量冲突 (2)可以封装 (3)阅读性好 2.static 数据成员独立于该类的任意对象而存在 static数据成员的类型可以是该成员所 ...
- java中static修改成员变量和函数和其他使用
一.通过static修饰的成员变量初始化只会初始化一次 //静态变量初始化只会初始化一次 public class zuishuai { public static void main(String[ ...
- C++ static类成员,static类成员函数
转载:ZJE_ANDY static修饰类中成员,表示类的共享数据 1.static类成员 C++primer里面说过,static类成员不像普通的类数据成员,static类数据成员独立于一切类对象处 ...
- C++之static类成员,static类成员函数
0.static修饰类中成员,表示类的共享数据 1.static类成员 在C++primer里面说过,static类成员不像普通的类数据成员,static类数据成员独立于一切类对象处在.static类 ...
- c/c++ 类成员变量,成员函数的存储方式,以及this指针在c++中的作用
c/c++ 类成员变量,成员函数的存储方式,以及this指针在c++中的作用 c++不会像上图那样为每一个对象的成员变量和成员函数开辟内存空间, 而是像下图那样,只为每一个对象的成员变量开辟空间.成员 ...
- C++嵌套类及对外围类成员变量的访问
C++嵌套类及对外围类成员变量的访问 在一个类中定义的类称为嵌套类,定义嵌套类的类称为外围类. 定义嵌套类的目的在于隐藏类名,减少全局的标识符,从而限制用户能否使用该类建立对象.这样可以提高类的抽象能 ...
- const与static类成员
const成员函数作用1. 不能修改类的成员变量,同时不能调用类的非const成员函数.(const成员函数中,this的类型是一个指向const类类型对象的const指针,const成员函数返回*t ...
- C++中static类成员
static局部变量 static局部变量确保不迟于在程序执行流程第一次经过该对象的定义语句时进行初始化 这种对象一旦被创建,在程序结束前不会被撤销.在该函数被多次调用的过程中,静态局部对象会持续存在 ...
- Objective-C类成员变量深度剖析
目录 Non Fragile ivars 为什么Non Fragile ivars很关键 如何寻址类成员变量 真正的“如何寻址类成员变量” Non Fragile ivars布局调整 为什么Objec ...
随机推荐
- Swift编程语言学习12 ——实例方法(Instance Methods)和类型方法(Type Methods)
方法是与某些特定类型相关联的函数.类.结构体.枚举都能够定义实例方法:实例方法为给定类型的实例封装了详细的任务与功能.类.结构体.枚举也能够定义类型方法:类型方法与类型本身相关联.类型方法与 Obje ...
- JavaScript语言基础知识11
JavaScript字符的比较. 在接下来的学习内容的开始,我们先来看一下alert()此功能,它是一个消息框. OK,接下来正式介绍代码: <HTML> <HEAD> < ...
- Installshield建立IE快捷方式的方法
原文:Installshield建立IE快捷方式的方法 实现方法:在project assistant里或者install design里随便建一个快捷方式,然后去install design里修改刚 ...
- iOS文档序列化(对象归档)
对象归档: 概念: 对象归档是指将对象写入文件保存在硬盘,当再次又一次打开程序时,能够还原这些对象.也称:对象序列化.对象持久化. 数据持久性的方式(事实上就是3类) 1,NSKeyedArchive ...
- html5 文件系统File API
前言: 在做浏览器上传图片的时候,一般采用form表单上传,这种上传无法预览图片,无法查看图片大小,无法知道图片的类型等等!那么在html5 File API提供了这些表单无法实现的功能,而且还支持拖 ...
- 【c++类的构造函数具体解释
】
一.构造函数是干什么的 class Dog { public: // 类Dog的构造函数 // 特点:以类名作为函数名,无返回类型 Dog() ...
- Byte[]、Image、Bitmap 之间的相互转换
原文:Byte[].Image.Bitmap 之间的相互转换 /// <summary> /// 将图片Image转换成Byte[] /// </summ ...
- linux服务创建及jq配置服务列表查看
1.应用背景 随着业务需求,后台处理服务不断增多,对于这些服务或后台程序的查看.更新操作越来越凌乱,所以我们首先需要一个服务列表查看工具,方便查看各 服务的端口.运行状态.jar包路径等等. 2.创建 ...
- WCF总结笔记
------------------------windowform承载服务步骤: (1)定义契约: using System; using System.Collections.Generic; u ...
- 动态代理 原理简析(java. 动态编译,动态代理)
动态代理: 1.动态编译 JavaCompiler.CompilationTask 动态编译想理解自己查API文档 2.反射被代理类 主要使用Method.invoke(Object o,Object ...