C++经典问题_04 静态成员和this指针

一. 静态成员

① 静态成员变量

静态成员变量就是普通的成员变量前面加上static关键字就是静态成员变量.

  1. 所有的对象共享同一份静态成员变量.
  2. 在编译阶段分配内存,存储在全局数据区
  3. 在类内声明,类外初始化,需要在类外单独分配空间.
  4. 生命周期不依赖任何的对象,为程序的整个生命周期.
  5. 即可以通过对象来访问,也可以通过类名来访问
/*----------------------------------------------------------------
* 项目: Classical Question
* 作者: Fioman
* 邮箱: geym@hengdingzhineng.com
* 时间: 2022/3/22
* 格言: Talk is cheap,show me the code ^_^
//----------------------------------------------------------------*/

#include <iostream>
using namespace std;
class Simple
{
public:
	Simple()
	{
		mSimpleCountPrivate++;
		cout << "Simple的构造函数被调用,已被构造的次数" << ++mSimpleCount << endl;
	}
	~Simple() {};

	int  get_obj_count(void)
	{
		return mSimpleCountPrivate;
	}

public:
	static int mSimpleCount;

private:
	static int mSimpleCountPrivate; // 私有的静态成员变量,外部不能直接访问
};

int Simple::mSimpleCount = 0; // 类的静态成员变量需要在类外分配内存空间
int Simple::mSimpleCountPrivate = 0; 


int main()
{

	Simple s1; // 第一次构造
	cout << "已经创建的对象的个数: " << Simple::mSimpleCount << endl;
	Simple s2; // 第二次构造
	cout << "已经创建的对象个数: " << s2.get_obj_count() << endl;
	Simple s3; // 第三次构造
	cout << "已经创建的额对象个数: " << s3.mSimpleCount << endl;
	system("pause");
	return 0;
}

结果:

② 静态成员函数
  1. 普通的函数前面加上static关键字就是静态成员函数
  2. 静态成员函数没有this指针,所以只能访问静态成员变量
  3. 所有的对象共享静态成员函数,无论对象是否已经创建,都可以访问静态成员函数
  4. 静态成员函数,不能调用普通的成员函数,只能调用静态的成员函数
  5. 普通的成员函数有this指针,可以访问内部的任意成员,而静态成员函数没有this指针,只能访问静态成员(静态成员变量和静态成员函数)
/*----------------------------------------------------------------
* 项目: Classical Question
* 作者: Fioman
* 邮箱: geym@hengdingzhineng.com
* 时间: 2022/3/22
* 格言: Talk is cheap,show me the code ^_^
//----------------------------------------------------------------*/

#include <iostream>
using namespace std;
class Student
{
public:
	Student(const char *name, int age, float score)
	{
		mName = name;
		mAge = age;
		mScore = score;
		mTotal++;
		mScores += mScore;
	}
	void show()
	{
		cout << mName << "的年龄是: " << mAge << ", 成绩是: " << mScore << endl;
	}

	static int get_total()
	{
		return mTotal;
	}
	static float get_scores()
	{
		return mScores;
	}
private:
	const char *mName;
	int mAge = 0;
	float mScore;
	static int mTotal; // 总人数
	static float mScores; // 总分数
};
// 定义静态成员变量
int Student::mTotal = 0;
float Student::mScores = 0.0;

int main()
{
	(new Student("张三", 15, 100))->show();
	(new Student("李四", 13, 89))->show();
	(new Student("王五", 12, 100))->show();
	(new Student("小明", 11, 82))->show();

	int total = Student::get_total();
	float scores = Student::get_scores();
	cout << "当前共有" << total << "名学生,总成绩是" << scores << ", 平均分是: " << scores / total << endl;

	system("pause");
	return 0;
}

结果:
在这里插入图片描述

二. 成员变量和成员函数分开存储

① 空对象占用字节的大小

在C++中,类内的成员变量和成员函数分开存储,只有非静态成员变量才属于类的对象上.
而一个空类它也是占用字节的,占用1个字节.

/*----------------------------------------------------------------
* 项目: Classical Question
* 作者: Fioman
* 邮箱: geym@hengdingzhineng.com
* 时间: 2022/3/22
* 格言: Talk is cheap,show me the code ^_^
//----------------------------------------------------------------*/

#include <iostream>
using namespace std;
class Empty
{
	// 空类什么都没有
};

int main()
{
	// 实例化两个对象
	Empty e1;
	Empty e2;
	cout << "e1 对象占用内存大小: " << sizeof(e1) << endl;
	cout << "e2 对象占用内存大小: " << sizeof(e2) << endl;

	cout << "e1 的地址: " << &e1 << endl;
	cout << "e2 的地址: " << &e2 << endl;
	system("pause");
	return 0;
}

结果:

分析

  1. 空类之所以会占用一个字节,其实这里是用来占位的
  2. 因为空类也可以实例化,如果不占用1个字节,就没办法分配内存.
  3. 当空类作为基类的时候,该类的大小就会被优化为0,这就是所谓的空白基类的最优化.
② 成员函数和变量分开存储
  1. 定义对象的时候会分配存储空间,但是只会为对象的成员变量分配存空间,成员函数则存放到公共的代码区.
  2. 每个对象占用的的存储空间只是该对象的数据部分,而不包括成员函数.
  3. 而成员函数存放在代码区,只有一份,那么怎么区分是哪个函数来调用的呢,通过this指针.

三. this指针

① 为什么需要this指针
  1. 在建立对象的时候,对象中的数据成员会分配自己独立的存储空间.但是对于成员函数来说,一个函数的代码段在内存中只有一份.也就是说,同一个类中的不同对象在调用自己的成员函数时,其实它们调用的是同一个函数代码.
  2. 既然是调用同一个代码段,那么如何确保调用的是自己的数据成员呢? 通过this指针.其实每一个成员函数中都有一个隐藏的参数,是一个指针,名字叫this.它的值是当前被调用的成员函数所在的对象的起始地址.其实就是当前对象存放数据的起始地址.所以其对数据的引用,其实是通过this-> 这种方式去操作this指向的对象.
② this指针的用途
  • 用途1: 当形参和成员变量同名时,可以用this指针来区分
/*----------------------------------------------------------------
* 项目: Classical Question
* 作者: Fioman
* 邮箱: geym@hengdingzhineng.com
* 时间: 2022/3/22
* 格言: Talk is cheap,show me the code ^_^
//----------------------------------------------------------------*/

#include <iostream>
using namespace std;
class Person
{
public:
	Person(string name,int age)
	{
		this->name = name;
		this->age = age;
	}

private:
	string name;
	int age = 0;
};

int main()
{
	Person p("Fioman", 18);
	system("pause");
	return 0;
}

  • 在类的非静态函数中返回对象本身,可使用return *this,用于链式编程.
/*----------------------------------------------------------------
* 项目: Classical Question
* 作者: Fioman
* 邮箱: geym@hengdingzhineng.com
* 时间: 2022/3/22
* 格言: Talk is cheap,show me the code ^_^
//----------------------------------------------------------------*/

#include <iostream>
using namespace std;
class Person
{
public:
	Person(int money)
	{
		this->money = money;
	}
	Person &add_money(Person &p)
	{
		this->money += p.money;
		return *this;
	}
public:
	int money = 0;
};

int main()
{
	Person p1(5);
	Person p2(100);
	Person p3(20);
	p1.add_money(p2); // 5 + 100 = 105
	p1.add_money(p2).add_money(p3); // 105 + 100 + 20 = 225
	cout << p1.money << endl;

	system("pause");
	return 0;
}
③ this指针使用的时候注意事项
  • this指针只能在成员函数中使用
  1. 全局函数,静态函数都不能使用this指针
  2. 实际上成员函数的第一个参数为 T * const this.
class A
{
public:
	// 这个函数的原型应该是int func(A* const this,int p){}
	int func(int p)
	{
		cout << "in func this 指针的地址: " << this << endl;
	}
};
  • this在成员函数开始前构造,在成员函数结束后清除
  1. 这个生命周期同任何一个函数的参数是一样的,没有任何区别.
  2. 当调用一个类的成员函数时,编译器将类的指针作为函数的this参数传递进去. 如: A a; a.func(10);
    其实编译器会翻译成A::func(&a,10);
  3. 编译器通常会对this指针做一些优化,因此,this指针的传递效率比较高.
  • this指针是什么时候创建的

在成员函数开始执行之前构造,在成员函数执行结束后清除

  • this指针存放在何处?堆,栈,全局变量,还是其他?

this指针会因编译器的不同而有不同的放置位置.可能是栈,也可能是期存器,甚至是全局变量.

  • this指针是如何传递类中的函数的

大多数的编译器通过ecx寄存器传递this指针.在call之前,编译器会把对应的对象地址放到eax中.this是通过函数参数的首参来传递的.this指针在调用之前生成.类在实例化的时候,只分配类中的数据成员的空间,并没有为函数分配空间.自从类定义完成以后,它就在那里,就一份.

  • this指针是如何访问结构体中的变量的

如果不是类,而是结构体的话,那么,如果通过结构体指针来访问结构体的变量呢?
在C++中,类和结构体只有一个区别: 类的成员默认是private的,而结构是public.
this是类的指针,如果换成结构体,那么this就是结构的指针了.

  • 我们只有获得一个对象后,才能通过对象this指针,如果知道了一个this指针的位置,可以直接使用吗?

this指针只有在成员函数中有定义.所以,你获取一个对象后,也不能通过对象使用this指针.所以,我们无法知道一个对象的this指针的位置(只有在成员函数中才有this指针的位置).知道了this指针的位置之后,可以直接使用它.

  • 每个类编译后,是否创建一个类中函数表保存函数指针,以便用来调用函数?

普通的类函数(不论是成员函数,还是静态函数)都不会创建一个函数表来保存函数指针.只有虚函数才会被放到函数表中.但是,即使是虚函数,如果编译器能明确知道用的是哪个函数,编译器就不会通过函数表中的指针来间接调用,而是会直接调用该函数.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值