const成员和static成员详解
- 1.const成员函数
- 2.static成员
- (1)静态成员变量
- (2)静态成员函数
- (3)静态成员使用场景
1.const成员函数
将const修饰的“成员函数”称之为const成员函数,const修饰类成员函数,实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对调用对象的任何成员进行修改。
**格式:**将const关键字放在函数的括号后面
以这种方式声明和定义的类函数被称为const成员函数,就像尽可能地将函数形参中的引用和指针声明为const一样,只要成员函数不修改调用对象,就应该将其声明为const,这样既可以避免调用对象被修改,而且普通对象和const对象都可以调用。
前面提到过,读写权限只能缩小,不能放大,同理,const对象不可以调用非const成员函数,一是因为这是权限的放大,二是因为非const成员函数无法确保调用对象不被修改。非const对象可以调用const成员函数,因为这是权限的缩小。
2.static成员
概念
声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量,用static修饰的成员函数,称之为静态成员函数。静态成员为所有类对象共享,类的对象都可以访问静态成员,所有类的成员访问的静态成员都是同一份静态成员。
(1)静态成员变量
特性
-
静态成员变量为所有类对象所共享,不属于某个具体类的对象,它是属于类的,只有一份内存,存放在静态区。比如说太阳,这里的太阳就可以指静态成员变量,所有人都能照射到,所有对象都可以访问到,且访问的就是同一个太阳。
-
在对象的构造函数中不能对静态变量进行初始化,因为静态变量不属于单个对象,不需要对象去初始化。静态成员变量在类中加static声明,静态成员变量必须在类外进行初始化定义,定义时不添加static关键字,即静态成员类中声明,类外进行初始化定义
-
类静态成员即可用类名::静态成员 或者 对象.静态成员 来访问,类名访问,肯定是从类外访问,那么类外访问的话,就要求静态数据成员是公有属性,可以用类名访问这一点也说明:静态数据成员肯定不是属于对象的,如果是属于对象,那么又怎么能用类名去访问呢?
-
静态成员也是类的成员,受public、protected、private 访问限定符的限制
-
静态成员变量只能初始化,不能赋值
如图,如果在类中进行初始化定义,编译器就会报错
改成如下,类中声明,类外定义就没有问题了
如果给静态成员变量赋值,编译器就会报错
(2)静态成员函数
定义方式:
- 类中声明,类外定义
- 类中定义
class ClassName
{
public:
static Type fun(){}//在类中定义
static Type fun2();//类中声明
};
Type ClassName::fun2(){}//在类外定义
在类外定义的时候不需要再加上static 如:static void ClassName::test_fun1(){},这样写是不对的,正确的类外定义应该是void ClassName::test_fun1(){}。
静态成员函数没有隐藏的this指针,不能访问任何非静态成员,因为可以通过类名直接去访问函数,那么过程中间不存在对象,this指针就没有对象去指向了,为了避免这种情况的发生,索性就静态函数中就不要this指针了,如果通过对象去调用,虽然可以正确调到,但是this指针也没了。
静态成员函数不可以访问普通成员变量,也不可以调用普通成员函数,由于静态成员函数和普通成员变量的生命周期不同,静态成员函数的生命周期是全局的,随着程序的结束而结束,普通成员变量是局部的,当对象消亡了,普通成员变量也就消亡了,如果静态成员函数访问普通成员变量,而普通成员变量消亡,就会造成非法访问的一个问题,所以静态成员函数不可以访问普通成员变量,但是普通函数可以调用,那么怎样避免静态成员函数调用的普通函数中调用了普通成员变量的情况呢?索性就一刀切,既不要访问普通成员变量也不访问普通成员函数。
普通成员函数可以访问静态成员变量,可以调用静态成员函数,静态成员函数只能访问静态成员变量,调用静态成员函数,不能访问任何非静态的东西。
(3)静态成员使用场景
因为静态成员是属于类而不是属于单个对象的,所以静态成员用来记录类相关的信息,比如,用静态成员来统计创建了多少个类的对象。
#include <iostream>
using namespace std;
class Person
{
private:
public:
int age; // 普通成员变量
static int cnt; //统计程序存在的中类的对象个数
Person(void); //构造函数
~Person(void); //析构函数
};
//在构造函数中cnt加一
Person::Person(void)
{
age = 18;
Person::cnt++; //方式1
//cnt++; //方式2
//this->cnt++; //方式3
}
//在析构函数中cnt减一
Person::~Person(void)
{
Person::cnt--;
}
// 对Person类中的静态成员定义
int Person::cnt;
int main(void)
{
cout << "Person::cnt = " << Person::cnt << endl;
Person *p1 = new Person();
cout << "Person::cnt = " << Person::cnt << endl;
Person *p2 = new Person();
cout << "Person::cnt = " << Person::cnt << endl;
Person *p3 = new Person();
cout << "Person::cnt = " << Person::cnt << endl;
delete(p1);
cout << "Person::cnt = " << Person::cnt << endl;
delete(p2);
cout << "Person::cnt = " << Person::cnt << endl;
delete(p3);
cout << "Person::cnt = " << Person::cnt << endl;
return 0;
}
运行结果如下:
(1)每次创建Person类的对象都会调用对象自己的构造函数,从上面的程序执行结果可以得出结果,每个对象的构造函数操作的cnt都是同一份cnt;
(2)析构函数也是如此;
总结:对象操作的类静态成员都是同一份;