C++--类的实例化

一、实例化的概念

用类类型在屋里内存中创建对象的过程,称为类实例化出对象

类是对对象进行一种抽象描述,是一个模型一样的东西,限定了类有哪些成员变量,这些成员变量只是声明,没有分配空间,用类实例化出对象时,才会分配空间。

一个类可以实例化出多个对象,实例化出的对象占用实际的物理空间,存储类成员变量。

举个例子:类实例化出对象就像现实中使用建筑设计图建造出房子,类就是设计图,设计图并不是实体化的建筑,只有当使用设计图修建出房子后,这个房子才能住人。类同理,它不能存储数据,实例化出的对象分配物理内存数据。

class Data
{
public:
	void Print(int year, int month, int day)
	{
		cout << year << "/" << month << "/" << day << endl;
	}

private:
	//此时并没有真正的开辟空间
	int _year;
	int _month;
	int _day;

};
//在这里会输出12个字节的大小,原因是此时编译器在编译期间需要确定占据的空间大小
//并不是真正的开辟空间,只有当对对象进行实例化的时候才会开辟相对应的空间
void Print()
{
	cout << "sizeof(d): " << sizeof(Data) << endl;
}

int main()
{
	Print();
	//在这里创建了Data d 这样的一个对象后Data类中的成员变量才是真正的开辟了空间
	Data d;
	cout << "sizeof(d): " << sizeof(d) << endl;
	d.Print(2024, 9, 14);
	return 0;
}

在 C++ 中,即使没有显式地对类的成员变量进行 “实例化”(初始化),但当定义类的对象时,依然会为对象分配内存空间以容纳类的成员变量。

在上述代码中,虽然没有显式地创建Data类的对象,但在Print函数中使用sizeof(Data)来获取Data类的大小,这并不意味着真正地为对象开辟了空间,只是在编译期确定这个类在内存中需要占据的空间大小。

类的大小取决于其成员变量的类型和布局,即使成员变量没有被初始化,它们在类的布局中仍然占据一定的空间,所以sizeof(Data)会返回一个非零的值,这并不代表实际开辟了对象的存储空间。只有在使用Data d;这样的语句创建类的对象时,才真正在运行时为对象分配内存空间。

二、对象大小

类实例化出的每个对象都有独立的数据空间,所以对象中包含成员变量。

函数在被编译后是一段指令,对象中没办法存储,所以一般情况下类的对象本身不直接包含函数指针。

同时C++中规定,类实例化的对象也要遵守内存对齐的规则。

class A
{
public:
private:
	char c;
	int i;
};

class B{};

class C{};

int main()
{
	A a;
	B b;
	C c;
	cout << sizeof(a) << endl;
	cout << sizeof(b) << endl;
	cout << sizeof(c) << endl;
}

上述代码中A类根据内存对齐的规则应当是8个字节的数据,输出的是没有问题的;

但是B类 和 C类的1个字节是什么原因呢?

原因如下:给定一个字符作为占位符的存在,否则无法证明类的存在,这个字节的空间不存储任何数据,仅作为占位符的作用存在。

三、this指针

在C++中存在一个隐藏的this指针,他的作用就是在编译器对代码进行编译后,在函数的参数中默认调用这个指针,用于解决函数中对不同对象的区分。

我们来看下面这段代码:

#define _CRT_SECURE_NO_WARNINGS 1

#include<iostream>
using namespace std;
class Date
{
public:
	// void Init(Date* const this, int year, int month, int day)
	void Init(int year, int month, int day)
	{
		// 编译报错:error C2106: “=”: 左操作数必须为左值
		// this = nullptr;
		// this->_year = year;
		_year = year;
		this->_month = month;
		this->_day = day;
	}
	void Print()
	{
	cout << _year << "/" << _month << "/" << _day << endl;
	}
private:
	// 这⾥只是声明,没有开空间
	int _year;
	int _month;
	int _day;
};
int main()
{
	// Date类实例化出对象d1和d2
	Date d1;
	Date d2;
	// d1.Init(&d1, 2024, 3, 31);
	d1.Init(2024, 3, 31);
	d1.Print();
	d2.Init(2024, 7, 5);
	d2.Print();
	return 0;
}

在上述代码中Data类又Init和Print两个成员函数,函数体中的没有关于不同对象的区分,此时就是使用了this指针来解决的这个问题。

编译器将其编译后,类的成员函数默认会在形参的第一个位置,增加一个当前类类型得到指针,叫做this指针。

也就是说其原型是Data(Data* const this,int year,int month,int day);

类的成员函数中访问成员变量,本质都是通过this指针访问的,如Init函数中给成员的赋值。

注意!C++中规定不能在实参和形参的的位置显示的写this指针,但是可以在函数体内显示使用this指针。

this指针的存放位置:内存中的栈区。

原因:this指针本身是函数的一个参数,而创建函数就会创建栈,当函数体销毁时,栈区也随之销毁,同时栈中的参数也会随之销毁,由此可见,this指针在内存中存放的位置是栈区。

四、C++和C语言实现Stack的区别

面向对象的三大特征:封装、继承、多态

区别:

1、C++中的数据和函数都放在了类里面,通过访问限定符进行了限制,不能再随意通过对象直接修改数据,这是C++封装的一种体现,这个是最重要的变化。

封装的本质就是一种更为严格规范的管理,避免出现乱访问修改数据的情况。

2、C++中有一些相对方便的语法,比如Init给的缺省参数会方便很对,成员函数每次不需要传对象地址,因为this指针隐含了传递,使用类型不再需要typedef来进行重定义,直接使用类名即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值