类的static成员

0.引言

1.静态(static)成员概述

  • 静态成员:不是任意对象的组成部分,但由给定类的全体对象所共享的数据成员或函数成员。
  • 静态成员是与类关联的对象,而不是像普通的成员那样与类的对象相关联。
  • 静态成员可以是数据成员,或成员函数。
  • 静态成员遵循正常的共有/私有访问规则。
  • 通过关键字static声明静态成员。

2,静态数据成员

2.1 定义方式

静态数据成员必须在类定义体的外部定义,且只能定义一次。静态数据成员不能通过类的构造函数初始化,而是应该在定义时进行初始化。
保证对象正好定义一次的方法是,将static数据成员的定义放在包含类的非内联成员函数定义的源文件中。

    // test.h
    // 定义类
    class Box
    {
    public:
    	Box() :len(0.0), width(0.0) {}
    	Box(double new_len, double new_width) :len(new_len), width(new_width) {}
    	double volume() { return len*width*height; }
     
    private:
    	double len;
    	double width;
    	static double height;//静态函数的成员变量也得是静态变量,但是静态变量的赋值需要在类外进行赋值
    };
     
    //test.c
    // 定义、初始化类的静态数据成员
    double Box::height = 10;//初始化赋值放到类外,如果头文件和源文件分开,则初始化需要在源文件中进行
     
    //在main()函数中使用该类
    int main()
    {
    	Box box1(1, 2);
    	cout << box1.volume() << endl;
    }

输出为120,即1210.在类的定义体外将静态成员height初始化为10.
  
  这里需要注意,如果是头文件和源文件分开,则静态成员变量的初始化需要在源文件中进行,如果在头文件中进行会报错:error LNK2001: 无法解析的外部符号
  
  注意:不要将静态成员的定义放在头文件中,除非保证该头文件不会被两个不同的源文件包含,不然会报重复定义错误,相当于是在两个源文件中都定义了同一个变量。对于这种同一头文件被不同源文件包含的情况,使用#ifndef或者#pragma once是没用的。这种预编译宏是为了解决一个源文件两次包含同一个头文件的问题。
同时,对静态数据成员的定义也不能放在main()函数里,否则编译报错:error C2655: “Box::height”: 当前范围内的定义或重新声明非法。正确的做法,就如上面所说,把它放在定义类的成员函数的源文件中。

2.2 const static数据成员

const static数据成员的值一经定义不能修改。
  
  特别地,当该const static成员是整型时,可以在类的定义体内初始化,但是仍然必须在类的定义体外定义,此时定义时可以不必,也不能再赋值了。如果在类的定义体内和该const static整型成员的定义处都赋值,会报重复初始化错误,哪怕赋的是相同的值。
  
  注意,这种在类的定义体内初始化的写法,只适用于整型!

// test.h
class Box
{
public:
	Box() :len(0.0), width(0.0) {}
	Box(double new_len, double new_width) :len(new_len), width(new_width) {}
	double volume() { return len*width*height; }
	static Box box;  //该类类型的静态数据成员
 
private:
	double len;
	double width;
	static double height;
	//static const double weight = 50.0; //必须是整型?!!error C2864: 带有类内初始值设定项的静态数据成员必须具有不可变的常量整型
	static const double weight;//不在类内给定初始值的static const则不要求必须是整型。好奇葩!!
	static const int iNr = 10;
	//const static double weight; //const 与static谁前谁后都可以
};
 
// test.c
double Box::height = 10;
const int Box::iNr;
const double Box::weight = 50.3;
Box Box::box(3, 4);
 
int main()
{
	Box box1(1, 2);
	
	cout << Box::box.volume() << endl;
	cout << Box::box.box.volume() << endl;
	cout << Box::box.box.box.volume() << endl;
}

为什么整型会有特殊待遇,感觉很奇葩。
  另外请注意,静态数据成员可以是本类类型的,而一般的成员最多是本类类型的指针或引用。上面的例子中几个cout的输出是相同的,都是120, 3410

3,静态成员函数

在声明成员函数时,在前面加static即成为静态成员函数。注意,只能在声明的时候加,在体外定义的时候,不能再加static限定,否则报错:error C2724: “Bar::callsFooVal”:“static”不应在文件范围内定义的成员函数上使用.
  
  静态成员函数与普通成员函数最大的区别是,其没有this指针,所以它不能直接使用类的非静态数据成员,但可以直接使用类的静态数据成员。如果一定要使用类的非静态数据成员,就一定要指明对象(估计该对象也只能是全局变量了)。但一般而言还是尽量不要这么使用。
  
  由于static成员不是任何对象的组成部分,没有this指针,不可能修改函数所属的对象,所以其也不能被限定为const。

// test.h
class Foo
{
public:
	Foo():iVal(0) {}
	Foo(int new_val) :iVal(new_val) {}
	int get_value() { return iVal; }
 
private:
	int iVal;
};
 
class Bar
{
public:	
	int FooVal() { iTimes++; return fool.get_value(); }// 普通的成员函数,也能使用静态数据成员
	static int callsFooVal() { return iTimes; } //使用了静态数据成员
 
private:
	static int iTimes;
	static int i;
	static Foo fool;
};
 
// test.c
Foo Bar::fool(3132);
int Bar::i = 520;
int Bar::iTimes = 0;
//int Bar::iTimes; //OK,自动赋0值
 
int main()
{
	Foo foo_1(520);
	cout << foo_1.get_value() << endl;
 
	Bar bar_1;
	Bar bar_2;
	cout << bar_1.FooVal() << " " << bar_2.FooVal() << endl;
	cout << Bar::callsFooVal() << endl;
}

最终输出:

520
3132  3132
2

注意,静态成员函数只能使用静态数据成员;但是普通的成员函数,既能使用普通的数据成员,也能使用静态数据成员。

4,类中的关键字出现位置总结

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值