我们正常情况下能通过对象名来访问 public 成员变量,每个对象的成员变量都是专属的,成员变量不能在对象之间共享的。我们现在学了这么长时间的 C++,现在又有了一个新的需求:a> 同级在程序运行期间某个类的对象数目;b> 保证程序的安全性(不能使用全局变量);c> 随时可以获取当前对象的数目。
我们首先想到的是定义一个私有成员变量,然后在构造函数中进行 ++ 操作,在析构函数中进行 -- 操作。我们试着写下程序
#include <stdio.h> class Test { private: int mCount; public: Test() { mCount++; } ~Test() { --mCount; } int getCount() { return mCount; } }; Test gTest; int main() { Test t1; Test t2; printf("gTest.getCount() = %d\n", gTest.getCount()); printf("t1.getCount() = %d\n", t1.getCount()); printf("t2.getCount() = %d\n", t2.getCount()); return 0; }
我们先来试着编译下
那么它打印出来的是都是随机值,我们在构造函数中的初始化列表中进行初始化为0
我们看到打印出三个 1,并不是我们所期望的三个 3。这是因为在每次新生成对象调用构造函数时,它都会初始化。那么我们试着定义一个全局变量来试试呢,int gMount = 0
显然它是可以满足的,但是我们的客户需求里有一条便是不准使用全局变量。所以这个只得放弃。这时我们便想到了静态成员变量,下来我们来讲讲静态成员变量。在 C++ 中可以定义静态成员变量:a> 静态成员变量属于整个类所有;b> 静态成员变量的声明周期不依赖于任何对象;c> 可以通过类名直接访问共有静态成员变量;d> 所有对象共享类的静态成员变量;e> 可以通过对象名访问公有静态成员变量。静态成员变量的特性:1、在定义时直接通过 static 关键字修饰;2、静态成员变量需要在类外单独分配空间;3、静态成员变量在程序内部位于全局数据区。它的语法规则是:Type ClassName::VarName = value;
下来我们使用静态成员变量来看看是否会满足要求,程序如下
#include <stdio.h> class Test { private: static int mCount; public: Test() : mCount(0) { mCount++; } ~Test() { --mCount; } int getCount() { return mCount; } }; Test gTest; int main() { Test t1; Test t2; printf("gTest.getCount() = %d\n", gTest.getCount()); printf("t1.getCount() = %d\n", t1.getCount()); printf("t2.getCount() = %d\n", t2.getCount()); return 0; }
我们编译下看看
我们看到报错了,要在全局数据区进行初始化,我们加上 int Test::mCount = 0;并且去掉构造函数中初始化列表的初始化,再次编译
我们看到已经实现了哈,那么我们是否可以放心的交给用户了哈。仔细看下,我们的程序没完成第三条需求,随时可以获取当前对象的数目。如果我们没有定义对象的话,那么我们这个程序是否还可以完成功能呢?肯定不行了。
那么我们尝试将 mCount 属性改为 public 呢,看看是否可以满足,程序如下
#include <stdio.h> class Test { public: static int mCount; public: Test() { mCount++; } ~Test() { --mCount; } int getCount() { return mCount; } }; int Test::mCount = 0; int main() { printf("mCount = %d\n", Test::mCount); return 0; }
结果如下
我们看到当没有定义对象的时候,它的数目是 0。但是这样做是不安全的,我们在 main 函数中将 mCount 手动改为 100,看看结果还是 0 吗?
我们看到它变成 100 了。也就是说,这是不安全的。所以这个方法不可取。那么我们这时就需要分析问题了,我们需要什么呢?不依赖对象就可以访问静态成员变量,必须保证静态成员变量的安全性,方便快捷的获取静态成员变量的值。在 C++ 中可以定义静态成员函数:a> 静态成员函数是类中特殊的成员函数;b> 静态成员函数属于整个类所有;c> 可以通过类名直接访问公有静态成员函数;d> 可以通过对象名访问公有静态成员函数。它的定义便是直接通过 static 关键字修饰成员函数。
下来我们试试静态成员函数,程序如下
#include <stdio.h> class Demo { private: int i; public: int getI(); static void staticFunc(const char* s); static void staticSetI(Demo& d, int v); }; int Demo::getI() { return i; } void Demo::staticFunc(const char* s) { printf("staticFunc: %s\n", s); } void Demo::staticSetI(Demo& d, int v) { d.i = v; } int main() { Demo::staticFunc("mian begin..."); Demo d; Demo::staticSetI(d, 10); printf("d.i = %d\n", d.getI()); Demo::staticFunc("mian end..."); return 0; }
结果如下
那么我们试试能否直接在 staticSetI 函数中对 i = v 呢?(去掉 Demo& d),我们试试
它报错了,因为静态成员函数不能直接访问普通成员变量。下面我们关于静态成员函数和普通成员函数的区别做了一个对比,如下图所示
那么关于我们之前提出的需求,我们可以利用静态成员函数来满足,程序如下
#include <stdio.h> class Test { private: static int mCount; public: Test() { mCount++; } ~Test() { --mCount; } static int getCount() { return mCount; } }; int Test::mCount = 0; int main() { printf("mCount = %d\n", Test::getCount()); Test t1; Test t2; printf("t1.getCount() = %d\n", t1.getCount()); printf("t2.getCount() = %d\n", t2.getCount()); Test* pt = new Test(); printf("t2.getCount() = %d\n", pt->getCount()); delete pt; printf("t2.getCount() = %d\n", pt->getCount()); return 0; }
我们看看编译结果
我们看到已经满足客户的需求了。通过对静态成员变量和函数的学习,总结如下:1、类中可以通过 static 关键字定义静态成员变量;2、静态成员变量隶属于类所有,每一个对象都可以访问静态成员变量;3、静态成员变量在全局数据区分配空间,它的生命周期为程序运行期;4、静态成员函数是类中特殊的成员函数;5、静态成员函数没有隐藏的 this 指针,它可以通过类名直接访问;6、静态成员函数只能直接访问静态成员变量(函数)。
欢迎大家一起来学习 C++ 语言,可以加我QQ:243343083。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。