C++学习笔记34——类的static成员

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,即1*2*10.
我们在类的定义体外将静态成员height初始化为10.
注意:不要将静态成员的定义放在头文件中,除非你能保证该头文件不会被两个不同的源文件包含,不然会报重复定义错误,相当于是在两个源文件中都定义了同一个变量。对于这种同一头文件被不同源文件包含的情况,使用#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,  3*4*10

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、付费专栏及课程。

余额充值