【编码的法则】谨慎的使用static

概述

static主要有三种使用方式,其中前两种在C/C++中使用,第三种只在C++语言中使用
1)静态局部变量
2)静态全局变量/函数
3)静态成员变量/函数

3 静态成员变量/函数

3.1静态成员变量

静态成员是C++所特有的,在类内数据成员的声明前加上关键字static,该数据成员就是类的静态数据成员了。

class CGame
{
public:
	CGame();
	virtual ~CGame();
	void drawGameArea();
	void drawGameInfo();
	void changeInfo();
	void run();
	bool checkFailed();
	bool checkLevel();
public:
	static const int KLEFT;
	static const int KUP;
	static const int KWIDTH;
	static const int KHEIGHT;
	static const int KSCORE_OFFSET;
	static const int KLEVEL_OFFSET;
private:
	CFood *m_pFood;
	CSnake *m_pSnake;
	int m_iScore;  //游戏得分
	int m_iLevel;  //关卡设置
};

以上的代码中

	static const int KLEFT;
	static const int KUP;
	static const int KWIDTH;
	static const int KHEIGHT;
	static const int KSCORE_OFFSET;
	static const int KLEVEL_OFFSET;

就是类的静态成员。
static成员变量的特点:

  • 静态数据成员和普通数据成员一样遵从public,privateed,protected访问规则
  • 静态数据成员初始化的格式为:
<数据类型><类名>::<静态数据成员名>=<值>

实例如下:

//静态成员变量的初始化
const int CGame::KLEFT = 5;
const int CGame::KUP = 2;
const int CGame::KWIDTH = 70;
const int CGame::KHEIGHT = 20;
const int CGame::KSCORE_OFFSET = 50;
const int CGame::KLEVEL_OFFSET = 65;
  • 无论类的对象被定义了多少个,静态数据成员在程序中只有一份拷贝,由该类型的所有对象共享访问。
    类中定义了静态成员变量,一定要记得初始化!
    参考:https://www.cnblogs.com/Manual-Linux/p/10996457.html 《C++使用静态类成员时出现的一个问题》

3.2静态成员函数

静态成员函数同静态成员变量一样,它为类服务而不是为类的具体对象服务。一般普通成员函数都隐含一个this指针,this指针指向类的对象本身,而静态成员函数不存在this指针,因为静态成员函数不属于任何对象,它属于类。静态成员函数无法访问类对象的非静态成员(包括非静态数据成员和非静态成员函数)。
可以采用下述格式进行静态成员函数的调用

<类名>::<静态成员函数名>(<参数表>)

小心陷阱
1 静态成员函数可以访问静态成员,但绝不能访问非静态成员。
2 静态成员不能声明为虚函数。这是因为静态成员函数在对象实例未生成前便可以调用。而如果对象实例未产生,虚函数调用使用的虚函数表未生成,导致虚函数调用时不知调用子类的虚函数还是父类的虚函数
【实际的应用】
在俄罗斯方块项目中,为了绘制方便,需要改变光标的位置,因此需要实现一个函数

void gotoxy(int x,int y)  

在C++的体系中,不希望把gotoxy()作为一个游离的全局函数,所以用一个类来单独的实现这个函数,同时又希望这个函数可以随时随地的使用,就把它编写为一个类的静态成员函数。如果真的声明成一个类的函数,每次用的时候,都要实例化一个对象,这样就太麻烦了。
gotoxy()函数的实现

#include "CCommFunc.h"
#include<Windows.h>

void CCommFunc::gotoxy(int x, int y)
{
	COORD cd;
	cd.X = x;
	cd.Y = y;
	//SetConsoleCursorPosition()函数用来设置控制台光标位置
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),cd);	
}

该函数的使用

/*******************************************
Description:  绘制主窗体程序
Input:  int needLayers 当前通关所需要的层数
		int currentLayers 当前已经消去的层数
Ouput:  无
Return:  无
Others: 无
*********************************************/
void CInfoBoard::drawInfoBoard(int needLayers, int currentLayers)
{
	if (needLayers < currentLayers)
	{
		return;
	}
	CCommFunc::gotoxy(this->m_offsetX,this->m_offsetY);
	cout << "------------------------";
	CCommFunc::gotoxy(this->m_offsetX,this->m_offsetY + 1);
	cout << "   NEED: " << needLayers << "     ";
	CCommFunc::gotoxy(this->m_offsetX, this->m_offsetY + 2);
	cout << "   NOW: " << currentLayers << "     ";
	CCommFunc::gotoxy(this->m_offsetX, this->m_offsetY + 3);
	cout << "-------------------------";
}
  • 2019-7-16 更新:静态成员函数没有this指针

今天在写代码的时候,Create()函数在类中的声明如下所示

static IController* Create(IControllerFactory* f);

在实现Create()函数时候,不自觉的使用了this,导致编译器报错

IController* IController::Create(IControllerFactory* f)
{
    if(!f)
    {
        return nullptr;
    }
    this->m_f = f;
    IController* c = f->CreateC();
//    c->m_f = f;
    c->m = f->CreateM();
    c->v = f->CreateV();

    return c;
}

提示错误为:

error: C2355: “this”: 只能在非静态成员函数或非静态数据成员初始值设定项的内部引用

posted @ 2019-06-13 17:24  尚修能的技术博客  阅读(454)  评论(0编辑  收藏  举报