类和对象(上)

目录

1.类的引用

2.类的定义

3.类的访问限定符

4.封装

5.类的作用域

6.类的实例化

7.类对象模型

7.1 类对象的大小

 7.2 结构体内存对齐规则

 8.this指针

8.1 this指针的引用

8.2 this指针的特性


1.类的引用

C语言struct结构体中只能定义变量,在c++中,结构体内不仅仅可以定义变量,也可以定义函数。比如:C语言实现数据结构的栈结构体只能定义变量,现在以c++方式实现,可以在结构体内定义函数。

typedef int DataType;

struct Stack
{
	void init()
	{
		DataType* tmp = (DataType*)malloc(4 * sizeof(DataType));
		if (tmp == nullptr)
		{
			perror("malloc fail");
			return;
		}
		_nums = tmp;
		_size = 0;
		_capacity = 4;
	}
	void destroy()
	{
		if (_nums)
		{
			free(_nums);
			_nums = nullptr;
			_size = 0;
			_capacity = 0;
		}
	}
	void push(int x)
	{
		if (_size == _capacity)
		{
			DataType* tmp = (DataType*)realloc(_nums, 2 * _capacity * sizeof(DataType));
			if (tmp == nullptr)
			{
				perror("realloc fail");
				return;
			}
			_nums = tmp;
			_capacity = 2 * _capacity;
		}
		_nums[_size] = x;
		_size++;
	}
	bool empty()
	{
		if (_size == 0)
			return true;
		else
			return false;
	}
	void pop()
	{
		if (!empty())
		{
			_size--;
		}
	}
	DataType top()
	{
		if (!empty())
		{
			return _nums[_size - 1];
		}
		else
		{
			return INT_MIN;
		}
	}
	//...
	DataType* _nums;
	int _size;
	int _capacity;
};

c++兼容c中的struct的用法,c++升级struct为类,在c++中更喜欢用class来替换;

2.类的定义

class className
{
  //类体:由成员变量和成员函数组成
};

class为定义类的关键字,className为类的名字,{}中为类的主体,注意类定义结束时后面的分号不能省略;
类体中:类体中的变量称为类的属性成员变量; 类体中的函数称为类的方法成员函数;
类的两种定义方式:
1.声明与定义不分离,全部在类体中(注意:成员函数如果在类中定义,编译器可能会将其当成内联函数处理)

class A
{
public:
	void func()
	{
		cout << "func()" << endl;
	}
private:
	int _a;
	int _b;
};

2.声明与定义分离,类声明放在.h文件中,成员函数定义放在.cpp文件中,注意:成员函数名前需要加类名::来指明类域

 一般情况下,用第二种方式将声明与定义分离;

成员变量一般加个前缀或者后缀标识区分:

3.类的访问限定符

C++实现封装的方式:用类将对象的属性与方法结合在一块,让对象更加完善,通过访问权限选
择性的将其接口提供给外部的用户使用
 
访问限定符:public(公有)、protected(保护)、private(私有)
访问限定符说明:
1. public修饰的成员在类外可以直接被访问
2. protected和private修饰的成员在类外不能直接被访问(此处protected和private是类似的,但是有区别的)
3. 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止
4. 如果后面没有访问限定符,作用域就到 } 即类结束。
5. class的默认访问权限为private,struct为public(因为struct要兼容C)

注意:访问限定符只在编译时有用,当数据映射到内存后,没有任何访问限定符上的区别

4.封装

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

先说封装:
封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互

在C++语言中实现封装,可以通过类将数据以及操作数据的方法进行有机结合,通过访问权限来
隐藏对象内部实现细节,控制哪些方法可以在类外部直接被使用

5.类的作用域

类定义了一个新的作用域,类的所有成员都在类的作用域中,在类体外定义成员时,需要使用:: 作用域操作符指明成员属于哪个类域,例如类的成员函数声明与定义分离。

6.类的实例化

用类 类型创建对象的过程称为类的实例化

1. 类是对对象进行描述的,是一个模型一样的东西,限定了类有哪些成员,定义出一个类并没
有分配实际的内存空间来存储它;比如:入学时填写的学生信息表,表格就可以看成是一个
类,来描述具体学生信息。
2. 一个类可以实例化出多个对象,实例化出的对象 占用实际的物理空间,存储类成员变量
也就是说类内的成员变量相当于声明,来指明类型和名字,此时还没有开空间:

 定义是在对象的实例化的时候,此时会开空间

7.类对象模型

7.1 类对象的大小

同一个类实例化的多个对象,每个对象的成员变量都是对象自己的,成员函数都是公共(公共代码区/代码段)的,所以计算一个类的大小是只计算成员变量的内存对齐后的大小

对象的占用的大小,只考虑成员变量(内存对齐)

 7.2 结构体内存对齐规则

1. 第一个成员在与结构体偏移量为0的地址处。
2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
(注意:对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值
VS中默认的对齐数为8)
3. 结构体总大小为:最大对齐数(所有变量类型最大者与默认对齐参数取最小)的整数倍。
4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整
体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

关于结构体和内存对齐可以看: 自定义类型:结构体-CSDN博客

特殊:空类(或类中只有成员函数)的大小--是1

定义的核心是开空间,空类大小是一个字节,不存储有效数据,标识对象被定义出来(大小是0就没有开空间,就不存在定义了)

 8.this指针

8.1 this指针的引用

先看代码:

class Date
{
public:
	void Init(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void Print()
	{
		cout << _year << '-' << _month << '-' << _day << endl;
	}

private:
	int _year;
	int _month;
	int _day;
};


int main()
{
	Date d1;
	d1.Init(2024, 5, 20);
	Date d2;
	d2.Init(2024, 5, 19);
	d1.Print();
	d2.Print();

	return 0;
}

 可能会有人疑惑:Date类中的Init和Print成员函数,函数体中没有关于不同对象的区分,所有对象共用一个函数,那当d1和d2调用函数时,函数怎么知道应该设置d1对象和d2对象呢?

C++中通过引入this指针解决该问题,即:C++编译器给每个“非静态的成员函数“增加了一个隐藏
的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有“成员变量”
的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编
译器自动完成

8.2 this指针的特性

1. this指针的类型:类类型* const,即成员函数中,不能给this指针赋值。
2. 只能在“成员函数”的内部使用
3. this指针本质上是“成员函数”的形参,当对象调用成员函数时,将对象地址作为实参传递给
this形参。所以对象中不存储this指针
4. this指针是“成员函数”第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传
递(也可能存在栈中),不需要用户传递

void Init(int year, int month, int day)
{
	_year = year;
	_month = month;
	_day = day;
}
this指针是隐藏在第一位的形参
//void Init(Date* const this, int year, int month, int day)
//{
//	this->_year = year;
//	this->_month = month;
//	this->_day = day;
//}
// 1.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class A
{
public:
 void Print()
 {
 cout << "Print()" << endl;
 }
private:
 int _a;
};
int main()
{
 A* p = nullptr;
 p->Print();
 return 0;
}

由特性3:this指针本质上是“成员函数”的形参,当对象调用成员函数时,将对象地址作为实参传递给this形参。所以对象中不存储this指针。可知,p->Print()实际上是将nullptr传给了Print函数,并没有对nullptr进行访问(传一个空指针没有问题),Print函数内部也没有对this(nullptr)进行访问,所以整体下来不会报错,选C

// 1.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class A
{
public:
	void Print()
	{
		cout << "Print()" << endl;
		cout << _a << endl;;;
	}
private:
	int _a;
};
int main()
{
	A* p = nullptr;
	p->Print();
	return 0;
}

 Print对this(nullptr)进行了访问,对nullptr进行访问会崩溃,选B

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

饼干烧饼

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

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

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

打赏作者

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

抵扣说明:

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

余额充值