【三、类中的静态成员】静态成员变量与静态成员函数(static关键字、this指针)

基本语法

  • 静态成员提供了一个同类对象的共享机制,静态成员变量属于整个类,该类所定义的对象共享同一个静态成员变量(无论定义多少个对象,他们的static成员变量都是同一个)。
  • 静态成员变量必须在外部声明并初始化。
  • 静态成员函数中不能使用非静态成员变量,因为静态成员函数提供不依赖于类数据结构的共同操作,它没有this指针。静态成员是属于整个类的,他不依赖于某个对象,而普通成员函数专属于类定义的个某个对象,这时候如果调用该静态成员函数,编译器不知道该函数中被引用的普通成员变量属于哪个具体对象,故报错(具体将在下面代码中详细分析)。

代码分析

代码如下:

#include <iostream>
using namespace std;

class MyClassA
{
public:
	MyClassA()
	{
		a = 10;
		cout << "无参构造函数调用" << endl;
	}

	void PrintA()
	{
		cout << "静态成员 a = " << a << endl;
	}

public:
	static int a;

};

int MyClassA::a = 0; //必须在外部定义!!!否则报错
					 //错误	LNK2001	无法解析的外部符号 "public: static int MyClassA::a" 

//静态成员变量测试
void FuncTest1()
{
	MyClassA A1, A2;
	A1.PrintA();

	//静态成员变量的第一种访问方式
	A2.a++;
	A1.PrintA();

	//静态成员变量的第二种访问方式
	MyClassA::a++;
	A1.PrintA();
	A2.PrintA();
}

class MyClassB
{
public:
	static void PrintStaticValue()
	{
		cout << "静态成员函数中的静态变量   " << "b2 = " << b2 << endl;
	}
	static void PrintValue()
	{
		//cout << "静态成员函数中的非静态变量   " << "b1 = " << b1 << endl;
		//错误(活动)	E0245	非静态成员引用必须与特定对象相对
		//错误	C2597	对非静态成员“MyClassB::b1”的非法引用	
	}
	/*
	静态成员函数中只能使用静态变量,不能使用非静态成员变量,因为非静态成员变量是属于某个对象的,
	当我们  MyClassB::PrintValue() 的时候,编译器不知道该使用哪个对象(B1还是B2还是B3...)的非
	成员变量b1
	*/

private:
	int b1;
	static int b2;

};

int MyClassB::b2 = 0;

//静态成员函数测试
void FuncTest2()
{
	MyClassB B;

	//静态成员函数的第一种调用方式
	B.PrintStaticValue();

	//静态成员函数的第二种调用方式
	MyClassB::PrintStaticValue();

	MyClassB B1, B2, B3;
	//MyClassB::PrintValue();
	//我应该使用哪个b1???是打印B1的b1,还是打印B2的b1,又或者是B3的b1?
	//故报错
}

int main()
{
	FuncTest1();
	FuncTest2();

	system("pause");
	return 0;
}

成员变量与成员函数的存储与this指针

C++类对象中的成员变量和成员函数是分开存储的

  • 成员变量:
    ①普通成员变量:存储于对象中,与struct变量有相同的内存布局和字节 对齐方式。
    ②静态成员变量:存储于全局数据区中。
  • 成员函数:存储于代码段中。

既然类的成员函数存储在代码区,也就是说所有的对象共用一块代码,那么当具体对象调用成员函数的时候,怎么区分成员函数中使用的变量是哪个对象的呢?比如:

class MyClass
{
public:
    void PrintValue()
    {
        a = 10;
        cout << a << endl;
    }
public:
    int a;
};

int main()
{
    MyClass A1, A2, A3;
    A1.PrintValue();
    
    system("pause");
    return 0;
}

在上段代码中,PrintValue函数中用的变量a是A1的还是A2的还是A3的呢?
C++编译器会对成员函数进行内部处理,加一个this指针,this指针指向调用该成员函数的对象,这样就知道是哪个对象调用了该成员函数,并使用该对象的成员变量值。代码如下:

void PrintValue(MyClass* this)
{
	this->a = 10;
    cout << this->a << endl;
}

在调用的时候

A1.PrintValue();

会被转化为

PrintValue(&A1);

由此可见,这也是使用了C语言的指针实现的。实际上,面向对象也是在面向过程的基础上实现的,只不过是在此基础上加了一层封装,对用户进行了隐藏而已。
对于静态成员函数,不会做这种转化,因为静态成员函数是属于整个类的,这也正是为什么静态成员函数中不能使用非静态成员变量,因为静态成员函数中没有this指针,编译器不知道使用的成员变量是哪个对象的变量。
普通成员函数都包含指向具体对象的this指针,哪个对象调用成员函数,this指针就指向这个对象。

系列文章

【二、new与delete详解】

【四、const与this指针详解】详解C与C++中const的异同,类中的const

posted @ 2022-02-20 13:26  Mindtechnist  阅读(49)  评论(0编辑  收藏  举报  来源