【029】C++类对象中的静态成员和 this 指针详解

本文详细介绍了C++中的静态成员,包括静态成员变量、静态成员函数以及它们在内存中的存储情况。此外,还讨论了this指针的作用,如何在成员函数中使用this指针,以及const修饰成员函数的限制。最后,通过单例模式展示了静态成员在设计模式中的应用。
摘要由CSDN通过智能技术生成

引言


💡 作者简介:专注分享高性能服务器后台开发技术知识,涵盖多个领域,包括C/C++、Linux、网络协议、设计模式、中间件、云原生、数据库、分布式架构等。目标是通过理论与代码实践的结合,让世界上看似难以掌握的技术变得易于理解与掌握。
💡 公众号:Lion 莱恩呀

👉
🎖️ CSDN实力新星、专家博主,阿里云博客专家、华为云云享专家
👉
🔔 专栏介绍:从零到c++精通的学习之路。内容包括C++基础编程、中级编程、高级编程;掌握各个知识点。
👉
🔔 专栏地址:C++从零开始到精通
👉
🔔 博客主页:https://blog.csdn.net/Long_xu


🔔 上一篇:【028】C++ 类和对象的 构造函数、析构函数、拷贝构造、初始化列表 详解(最全讲解)
🔔 下一篇:【030】C++类和对象之友元(friend)详解

一、静态成员

C++静态成员是指属于类而不是属于对象的成员。与普通成员变量和函数不同,静态成员变量和函数在内存中只有一份副本,无论类实例化了多少次,它们都是共享的。

在类的定义中,它的成员(包括成员变量、成员函数)可以使用关键字static声明为静态的,称为静态成员。不管这个类创建了多少个对象,静态成员只有一个拷贝,这个拷贝被所有属于这个类的对象共享。使用静态成员可以实现对类级别的操作。

使用方法:

  1. 声明静态成员变量或函数:在类声明中使用 static 关键字来声明静态成员变量或函数。

  2. 定义静态成员变量或函数:在类外部用作用域解析运算符(::)定义静态成员变量或函数。

1.1、静态成员变量

static修饰的静态成员属于类而不是对象,所有的对象共享一份静态成员数据。例如:

class Data{
private:
	int a;
	int b;
	int c;

	static int d;
};

实例化时它的内存布局:
在这里插入图片描述
静态成员变量中,需要清楚以下几点:

  • static修饰的成员,定义类的时候必须分配空间。
  • static修饰的静态成员数据必须类中定义类外初始化。

示例:

#include <iostream>
using namespace std;
class Data{
private:
	// 普通成员变量
	int a;
	int b;
	int c;
	// 类中定义静态成员变量
	static int d;
};
// 类外初始化静态成员变量,不用加static
int Data::d=100;

int main()
{
	// 静态成员变量可以通过类名称直接访问
	cout<<Data::d<<endl;
	// 静态成员变量可以通过对象访问(对象间共享)
	Data ob1;
	cout<<ob1.d<<endl;

	Data ob2;
	Ob2.d=200;
	Data ob3;
	Ob3.d=300;
	// 共享
	cout<<ob1.d<<endl;
	// 静态成员变量可以通过类名称直接访问
	cout<<Data::d<<endl;
	return 0;
}

输出:

100
100
300
300

1.2、静态成员变量的使用示例

使用静态成员数据统计对象的个数。

#include <iostream>
using namespace std;
class Data{
public:
	int mA;
	static int count;
public:
	Data() {
		mA=0;
		count++;
	}
	Data(int num) {
		mA=num;
		count++;
	}
	Data(const Data &ob) {
		mA=ob.mA;
		count++;
	}
	~Data() {
		count--;
	}
};

int Data::count=0;

int main()
{
	Data ob1;
	Data ob2(100);
	Data ob3=ob2;
	cout<<"对象个数:"<<Data::count<<endl;
	{
		Data ob4;
		Data ob5;
		cout<<"对象个数:"<<Data::count<<endl;
	}
	cout<<"对象个数:"<<Data::count<<endl;
	return 0;
}

输出:

对象个数:3
对象个数:5
对象个数:3

这里使用的是public权限的静态成员变量,如果是privateprotected权限的,必须使用函数才能访问变量。

1.3、静态成员函数

静态成员函数属于类而不是对象,所有的对象共享。

class Data{
	static void func()
	{
	}
};

静态成员函数中,需要清楚以下几点:

  • 静态成员函数可以直接通过类名称访问。
  • 静态成员函数内只能操作静态成员变量。因为静态成员属于类,在类定义时就创建了,所有开辟了内存空间,可以访问,但是普通成员是类实例化为对象是才开辟空间,所有静态成员函数内只能操作静态成员变量。

示例:

#include <iostream>
using namespace std;

class Data{
private:
	int data;
	static int mA;
public:
	static int getA()
	{
		// data = 200;//error,不可以操作普通变量
		return mA;
	}
};

int Data::mA=100;
int main()
{
	// 静态成员函数可以直接通过类名称访问。
	cout<<Data::getA()<<endl;
}

1.4、单例模式设计

步骤:

  • 防止类在外界实例化对象,将构造函数私有化(包括无参构造、有参构造、拷贝构造)。
  • 定义一个静态的指针变量,保存唯一实例的地址。
  • 获取唯一的实例地址;提供静态成员函数。
  • 定义任务函数。

示例:

#include <iostream>
using namespace std;

class SingleTon {
	// 将构造函数私有化,防止类在外界实例化对象
private:
	SingleTon() {}
	SingleTon(const SingleTon &ob) {}
	~SingleTon() {}
private:
	// 定义一个静态指针变量,保存唯一实例的地址
	static SingleTon* const p;
public:
	// 提供一个静态成员函数,返回唯一实例的地址
	static SingleTon* getSingleTon(void)
	{
		return p;
	}
	// 定义的任务函数
	void printData(const char *str)
	{
		cout << "打印:" << str << endl;
	}
};

// 实例化对象
SingleTon* const SingleTon::p = new SingleTon;

int main()
{
	SingleTon *p1 = SingleTon::getSingleTon();
	p1->printData("hello sinleton");
	p1->printData("Lion");
	p1->printData("Tom");

	SingleTon *p2 = SingleTon::getSingleTon();
	p2->printData("hi sinleton");
	p2->printData("Long");
	p2->printData("Lucien");
	return 0;
}

二、C++面向对象模型

2.1、成员变量和函数的存储

C++实现了“封装”、“数据”和数据处理操作(函数)分开存储。C++中的非静态成员变量直接内含在类对象中,成员函数虽然内含在class声明中,却不出现在对象中,每一份非内联成员函数只会产生一份函数实例。
例如:

class Data{
public:
	char a;
	int b;
	static int c;
public:
	void func(){}
};

在这里插入图片描述
sizeof(Data)的大小只是ab所占用空间大小(类的对象所占空间大小)。

示例:

#include <iostream>
using namespace std;

class Data01{
public:
	int mA;
};

class Data02{
public:
	int mA;
	static int data;
};

class Data03{
public:
	void func() {
		cout<<"Data02 func"<<endl;
	}
public:
	int mA;
	static int data;
};

class Data02{
public:
	void func() {
		cout<<"Data02 func"<<endl;
	}
	static void func02() {
		cout<<"Data02 static func02"<<endl;
	}
public:
	int mA;
	static int data;
};

int main()
{
	Data ob01;
	Data02 ob02;
	Data03 ob03;
	Data04 ob04;

	cout<<"sizeof(Data): "<<sizeof(ob01)<<endl;
	cout<<"sizeof(Data02): "<<sizeof(ob02)<<endl;
	cout<<"sizeof(Data03): "<<sizeof(ob03)<<endl;
	cout<<"sizeof(Data04): "<<sizeof(ob04)<<endl;

	return 0;
}

输出:

sizeof(Data): 4
sizeof(Data02): 4
sizeof(Data03): 4
sizeof(Data04): 4

可以看到:C++类对象中的变量和函数是分开存储的。

2.2、this 指针

C++的数据和操作也是分开存储的,并且每一个非内联成员函数只会诞生一份函数实例;也就是说多个类型相同的对象会公用一块代码;那么这块代码如何区分哪个对象调用自己呢?
在这里插入图片描述

对象1的数据
对象2的数据
对象3的数据
公用函数代码

C++通过提供特殊的对象指针:this指针,解决上述的问题;this 指针指向被调用的成员函数所属的对象。成员函数通过this指针即可 知道操作的是哪个对象的数据。this指针是一种隐式指针,隐含于每个类的非静态成员函数中。this指针无需定义,直接使用即可。
在这里插入图片描述
注意:静态成员函数内部没有this指针(因为this指针保存的是对象地址,而静态成员函数属于类,在对象出现之前就已经存在),静态成员函数不能操作非静态成员变量。

2.3、this 指针的应用

(1)函数形参和成员同名可以使用this指针解决。

#include <iostream>
using namespace std;

class Data{
public:
	int num;
public:
	Data(int num) {
		this->num=num;
		cout<<this<<endl;
	}
};

int main()
{
	Data ob(100);
	cout<<ob.num<<endl;
	cout<<&ob<<endl;
	return 0;
}

输出:

0x61fe8c
100
0x61fe8c

(2)this 指针来完成链式操作。

#include <iostream>
using namespace std;

class Data{
	Data& printData(const char *str) {
		cout<<str<<" ";
		return *this;//返回调用该成员函数的对象
	}
}
int main()
{
	Data().printData("hello,").printData("Lion").printData("Long");
}

输出:

hello, Lion Long

2.4、const修饰成员函数

const修饰成员函数时,const修饰this指针指向的内存区域,成员函数体内不可以修改本类中的任何普通成员变量,除非成员变量类型前面用mutable修饰。

示例:

#include <iostream>
using namespace std;

class Data {
public:
	int a;
	int b;
	mutable int c;
public:
	Data(int a,int b,int c) {
		this->a=a;
		this->b=b;
		this->c=c;
	}
	void show(void) const {
		//a=100;// error
		c=500;// OK
		cout<<a<<" "<<b<<" "<<c<<endl;
	}
};

int main()
{
	Data obj(100,200,300);
	obj.show();
}

输出:

100 200 500

三、总结

  1. 静态成员是类的属性,属于整个类而不是类的对象。可以在任何对象中访问它们,但不需要创建实例即可使用它们。

  2. 使用静态成员变量时,必须在其前面加上“类名::”来指定其作用域。例如:ClassName::staticMemberVariable

  3. 静态成员函数也属于整个类,可以直接通过类名调用,并且不能访问非静态成员变量和函数。

  4. 静态成员变量只有一个副本,在所有对象之间共享。当类的一个对象修改了这个变量时,其他对象也会受到影响。

  5. this 指针是指向当前对象的指针,在成员函数内部使用。它可以用来访问该对象的非静态成员变量和函数。

  6. 在静态成员函数中不能使用 this 指针,因为静态函数没有 this 指针。

在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Lion Long

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值