当前课程知识点:C++语言程序设计基础 > 第5章 数据的共享与保护 > 类的静态成员 > 静态函数成员(例5-5)
l类外代码可以使用类名和作用域操作符来调用静态成员函数。
l静态成员函数主要用于处理该类的静态数据成员,可以直接调用静态成员函数。
l如果访问非静态成员,要通过对象来访问。
例5-5具有静态数据、函数成员的 Point类
#include <iostream>
using namespace std;
class Point {
public:
Point(int x = 0, int y = 0) : x(x), y(y) { count++; }//构造函数
Point(Point &p) { //复制构造函数
x = p.x;
y = p.y;
count++;
}
~Point() { count--; }
int getX() { return x; }
int getY() { return y; }
static void showCount() {
cout << " Object count = " << count << endl;
}
private:
int x, y;
static int count; //静态数据成员声明,用于记录点的个数
};
int Point::count = 0;//静态数据成员定义和初始化,使用类名限定
int main() {
Point a(4, 5); //定义对象a,其构造函数回使count增1
cout << "Point A: " << a.getX() << ", " << a.getY();
Point::showCount(); //输出对象个数
Point b(a); //定义对象b,其构造函数回使count增1
cout << "Point B: " << b.getX() << ", " << b.getY();
Point::showCount(); //输出对象个数
return 0;
}
大家好
欢迎回来继续学习
C++语言程序设计
这一节我给大家介绍
静态函数成员
我们只是有了静态数据成员
那用什么函数
来处理这个静态数据呢
我们在此之前呢
定义了这些函数成员
都是属于对象的
比如说
我们要取出这个点的x坐标
y坐标
getx gety
像这样的函数
它肯定是一定与某个对象相关
每次调用这样的函数的时候
都要通过对象去调用
然后这个函数呢
它可以获得这种信息
是哪个对象调用了它
所以当你调用getx的时候
它肯定知道
把哪个对象的x坐标返回
它不回弄错的
但是现在我们定义了
类的静态数据成员以后
它不属于任一个对象
那该用什么样的函数去处理它呢
一般来说
我们就要相应的定义
静态的函数成员
来处理静态数据
静态函数跟非静态成员函数
它们之间的差别在哪儿呢
差别就在
当你进到函数体以后
这个函数体里面
能不能自己知道
是哪个对象调用了它
对于非静态的
属于对象的函数
它就能够知道谁调用了它
不是说哪个主调函数调用了它
是通过哪个对象调用了它
我们用对象名.函数名
去调用这个成员函数
那么静态函数呢
即使你也用
对象名.函数名的方式
去调用这个静态函数
它就不能知道
是通过哪个对象调用了它
所以静态成员函数
一般是不用来处理
这些属于对象的数据
像每个对象的x坐标 y坐标
这种数据
是不用来处理这种数据的
它是一般是专门用来处理
属于整个类的静态数据的
如果你一定要用
一个静态的成员函数
去处理非静态的数据成员
那你就得将
希望它处理的这个对象
作为参数传给它
这种差别
大家学了第六章以后
就会明白
它到底为什么了
到底为什么呢
为什么还有的函数能知道
是哪个对象调用了它
有的函数又不知道呢
实际上调用非静态函数的时候
隐含地将当前对象的某种信息
传给了它
这件事好象很神秘
怎么能隐含就传过去呢
大家不要急
第六章就给大家介绍
现在我们知道一般的规律是
类里如果需要静态数据成员的话
相应地我们定义静态的函数成员
去处理它
现在我们还是通过例题
来理解一下静态函数成员
这一次我们在Point类里面
就增加了一个静态函数成员
实际上这是前一个例子里面那个
显示点的总数的那个函数
当时没有作为静态成员来定义
现在我们加一个static
就把它作为静态成员
那我们来看看
这个类的类图
那么我们看
在这个类的类图中呢
最底下showCount这个函数
前面有个关键字static
就表示它是个静态成员
现在呢我们来看一下
这个类的代码
现在我们来看这个例题
这个例题在前一个例题的基础上
做了一点小小的修改
大部分都还是一样的
我们先看它的私有数据成员定义
还是有一个静态的变量count
用于记录点的个数
非静态的变量x y
表示每一个对象的x坐标 y坐标
这个静态成员呢
仍然是在类外定义和初始化
但是不同的是什么呢
我们在这儿
将这个showCount函数
也定义成静态的了
那么静态的函数
也是为整个类的所有对象
共有的函数
那么大家在这一点上呢
可能有些疑问
不是所有的函数都只有
在类里面的这种声明和定义
只有一份有效
不赋值多份存在对象名下
每个对象的存储空间
就是它自己的数据成员占的空间
函数代码没有存多份呢
怎么表现出这是个静态函数
是为整个类所共享的
那个是非静态函数
是属于某一个对象的呢
我们来看
这个函数它都干些什么
比如说像构造函数
赋值构造函数
它都是在构造
某一个特定对象的时候起作用
我们来看它给x作初始化
给y变量作初始化
这个赋值构造
赋值给x
参数对象的y赋值给y
这个操作的都是指定对象的成员
像这个getx gety
也是将指定对象的成员返回
那我们看调用的时候呢
像a.getx
那么它就知道
要将a对象的x坐标返回
为什么呢
我们在第六章将要讲指针
讲了指针以后会告诉大家
对于非静态的函数
实际上是有一个
类似指针传过去的
而静态函数通常用来
执行什么任务呢
通常用来处理静态数据成员
你可不能指望
在showCount函数里面
说输出点的x坐标 y坐标
千万不能那么写
为什么呢
你要是说在showCount函数里面
要输出x坐标
它去输出谁的x坐标 对吧
这个类有那么多点构造出来了
你让showCount这个静态函数
属于整个类
而不属于对象的函数
去输出一个x坐标
是不是完全不可以呢
也不是
你如果一定要让它输出
某个对象的x坐标
你就得显示的将这个对象
作为参数传给showCount
不然的话你在这里面泛泛地说
cout x cout y
它根本不知道
该输出谁的x y坐标
但是你让它输出count
它就知道
因为整个类只有一个count变量
为什么是这样
相信大家在这儿一定有这个疑问
你可以做个笔记把它记下来
等我们讲完第六章
你这个疑问就解决了
第六章在这个课程的下半部
希望大家能继续学习第六章
能够真正去理解
为什么静态的函数加了static
它一般来讲
就只能访问静态数据
这个count这样的数据
好 做了这样一点点修改以后
这个题比上一个例题
用起来就方便一些了
我们来看在主函数中
在根本没有建立任何一个点之前
一个点都没有构造之前
我就可以通过类名
去调用showCount
通过类名调用showCount
就可以将当前点的总数
输出来0个
当然构造了对象以后
你再调用showCount
构造了a以后
那它就是一个对象了
构造了b以后
是两个对象了
这个时候是不是大家还有疑问
我现在只能用类名
去调用showCount函数吗
我能不能仍然用对象名去调用它
也可以
大家课后可以把这个例题
修改一下
你试试在这个地方
写a.showCount
在这个地方写b.showCount
看看它是不是也能正确的编译
运行是不是也能出正确的结果呢
应该是能正确的
所以一个静态的成员函数
我们既可以通过类名
作用域分辨符去调用它
也可以通过
对象名.函数名的方式去调用它
都是可以的
-导学
--第1章导学
-计算机系统简介
--计算机系统简介
--计算机系统简介 测试题
-计算机语言和程序设计方法的发展
--计算机语言和程序设计方法的发展 测试题
-面向对象的基本概念
--面向对象的基本概念 测试题
-程序的开发过程
--程序的开发过程
--程序的开发过程 测试题
-信息的表示和储存
--计算机的数字系统
--数据的编码表示
--信息的表示和储存 测试题
-实验指导
-导学
--第二章导学
-C++语言概述
--C++语言概述 测试题
-基本数据类型、常量、变量
--程序举例
--基本数据类型、常量、变量 测试题
-运算与表达式
--运算与表达式 测试题
-实验二:简单程序设计(上)
-数据的输入和输出
--数据的输入和输出
--数据的输入和输出 测试题
-选择结构
--if语句
--switch语句
--选择结构 测试题
-循环结构
--for语句
--循环结构 测试题
-自定义类型
--自定义类型
--自定义类型
-第2章小结
--第二章小结
-实验二:C++简单程序设计(下)
-导学
--导学
-函数定义
--函数定义
--函数定义 测试题
-函数调用
--例3-2
--例3-3
--例3-4
--例3-5
--例3-6
--函数调用 测试题
-嵌套与递归
--例3-9
--例3-10
--嵌套与递归 测试题
-函数的参数传递
--函数的参数传递
--函数的参数传递 测试题
-引用类型
--引用类型 测试题
-含有可变参数的函数
--含有可变参数的函数 测试题
-内联函数
--内联函数 测试题
-constexpr函数
--CONSTEXPR函数课后习题
-带默认参数值的函数
--带默认参数值的函数 测试题
-函数重载
--函数重载 测试题
-C++系统函数
--C++系统函数习题
-第3章小结
--第三章小结
-实验三(上)函数的应用
-实验三(下)函数的应用
-导学
--导学
-面向对象程序的基本特点
--面向对象程序的基本特点 测试题
-类和对象
--类和对象的定义
--类和对象 测试题
-构造函数
--构造函数基本概念
--委托构造函数
--复制构造函数
--构造函数 测试题
-析构函数
--析构函数
--析构函数 测试题
-类的组合
--类的组合
--类的组合程序举例
--前向引用声明
--类的组合 测试题
-UML简介
--UML简介
--UML简介课后习题
-结构体与联合体
--结构体与联合体 测试题
-枚举类
--枚举类
--枚举类 测试题
-第4章小结
--第四章小结
-实验四(上)
--实验四(上)
-实验四(下)
--实验四(下)
-导学
--导学
-标识符的作用域与可见性
--标识符的作用域与可见性 测试题
-对象的生存期
--对象的生存期
--对象的生存期 测试题
-类的静态成员
--类的静态成员 测试题
-类的友元
--类的友元 测试题
-共享数据的保护
--共享数据的保护 测试题
-多文件结构和预编译命令
--多文件结构和预编译命令 测试题
-第5章小结
--小结
-实验五
--实验五
-导学
--导学
-数组的定义与初始化
--数组的定义与使用
--一维数组应用举例
--数组的定义与初始化 测试题
-数组作为函数的参数
--数组作为函数的参数 测试题
-对象数组
--对象数组
--对象数组 测试题
-基于范围的for循环
-指针的定义和运算
--指针的定义和运算 测试题
-综合实例
--综合实例
-实验六(上)
--实验六上
-指针与数组
--指针数组
--指针与数组 测试题
-指针与函数
--指针类型的函数
--指向函数的指针
--指针与函数 测试题
-对象指针
--对象指针
--对象指针 测试题
-动态内存分配
--动态内存分配 测试题
-智能指针
--智能指针
-vector对象
--vector对象
--vector对象 测试题
-对象复制与移动
--移动构造
--对象复制与移动 测试题
-字符串
--C风格字符串
--string类
--字符串 测试题
-第6章小结
--第六章小结
-综合实例
--综合实例
-实验六(下)
--实验六(下)