从零开始学C++之c++类和对象<中>

从零开始学C++之c++类和对象<中>

6.结构体内存对齐规则:

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

举个栗子:有如下代码计算下面结构体的大小:

using namespace std;
struct A
{
	//vs的默认对齐数是8
	int a;//4字节
	int b;//4
	double d;//8 
	int e;//4-20 默认对齐数的整数倍 24
};
struct B
{
	char a;//1
	double d;//8+8=16
	int c;//16+4=20
	char e;//21-24
};
struct B
{
	char a;//1
	double d;//8+8=16
	char e;//17
	A objA;//24+24=48
};

内存对齐中的一些题目:

  1. 为什么要进行内存对齐?
    主要目的是为了提高效率,获取数据时,一般是按照4个字节或者8个字节的代码块进行获取,进行内存对齐时,不用进行内容的切割和拼接,提高读取数据的效率
  2. 如何让结构体按照指定的对齐参数进行对齐?
    可以通过#pragma pack?=(num)来修改默认对齐数。
  3. 如何知道结构体中某个成员相对于结构体起始位置的偏移量?
    使用地址相减
A a;
	cout << (char*)&a.d - (char*)&a << endl;
  1. 什么是大小端?如何测试某台机器是大端还是小端,有没有遇到过要考虑大小端的场景
    大端:低地址存高位,高地址存低位;
    小端:高地址存低位,低地址存高位;
    测试大小端的方法:
using namespace std;
union A
{
	int a;
	char b;
};
void test1()
{
	A obja;
	obja.a = 1;
	if (obja.b)
		cout << "小端" << endl;
	else
		cout << "大端" << endl;
}
void test2()
{
	int a = 1;
	char* pa = (char*)&a;
	if (*pa)
		cout << "小端" << endl;
	else
		cout << "大端" << endl;

}

7.this指针

1.每一个非静态成员函数中,都有一个this指针;
2.作为函数的第一个形参;
3.this指向当前调用此函数的对象
4.this类型:类类型*const this 一般不会变化
5.只存在成员函数中
6. this指针本质上其实是一个成员函数的形参,是对象调用成员函数时,将对象地址作为实参传递给this
形参。所以对象中不存储this指针。
7. this指针是成员函数第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递

#include<iostream>
using namespace std;
class Date
{
public:
	//每一个非静态成员函数中,都有一个this指针;
	//作为函数的第一个形参;
	//this指向当前调用此函数的对象
	//this类型:类类型*const this 一般不会变化

	void Display()//void Display(this)
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}

	void SetDate(int year, int month, int day)
	{//void SetDate(this, int year, int month, int day)
		this->_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year; // 年
	int _month; // 月
	int _day; // 日
};
int main()
{
	Date d1, d2;
	d1.SetDate(2018, 5, 1);
	d2.SetDate(2018, 7, 1);
	d1.Display();
	d2.Display();
	return 0;
}

在这里插入图片描述

8.this指针可以为空,但是不能进行解引用
在这里插入图片描述

8.类的6个默认成员函数

如果一个类中什么成员都没有,简称为空类。任何一个类在我们不写的情况下,都会自动生成下面6个默认成员函数。
类的6个默认的成员函数包括:构造函数、析构函数、拷贝构造函数、赋值运算符重载函数、取地址操作符重载、const修饰的取地址操作符重载。

9.构造函数

9.1构造函数的概念

构造函数是一个特殊的成员函数,名字与类名相同**,创建类类型对象时由编译器自动调用**,保证每个数据成员都有 一个合适的初始值,并且在对象的生命周期内只调用一次。

9.2 特性

构造函数是特殊的成员函数,需要注意的是,构造函数的虽然名称叫构造,但是需要注意的是构造函数的主要任务并不是开空间创建对象,而是初始化对象。
其特征如下:

  1. 函数名与类名相同。
  2. 无返回值。
  3. 对象实例化时编译器自动调用对应的构造函数。
  4. 构造函数可以重载。构造可以重载,无参的话默认构造。
  5. 编译器自动生成的构造也是无参的构造函数 全缺省也是默认构造,没有显示定义任何一个构造函数,编译器会自动生成无参构造,否则不会自动生成。
  6. 任何一个构造函数(包括编译器自动生成的)都会自动调用自定义成员的默认构造,如果没有默认构造,编译器会报错

举个栗子:

class Date
{
public:
	// 1.无参构造函数
	Date()
	{}


	//全缺省:也是一种默认构造
	Date(int year=1, int month=1, int day=1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
		// 2.带参构造函数
	Date(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year;
	int _month;
	int _day;
};
void TestDate()
{
	Date d1; // 调用无参构造函数
	Date d2(2015, 1, 1); // 调用带参的构造函数
//不能显示调用构造函数
//d.Data(2020,2,2)
	// 注意:如果通过无参构造函数创建对象时,对象后面不用跟括号,否则就成了函数声明
	// 以下代码的函数:声明了d3函数,该函数无参,返回一个日期类型的对象
	//不是调用了无参构造,而是声明一个函数
	//函数名:d3
	//参数列表:空
	//返回值:Data
	Date d3();
}

9.3总结:

1.构造函数是初始化对象的内容,不是创建对象
2.创建对象时,编译器自动调用构造函数,不能显式调用
3.如果没有显式定义构造,则编译器自动生成无参构造,否则编译器不再生成无参构造。
4.默认构造只能有一个,无参构造和全缺省都是默认构造;
5.如果有自定义成员,则构造函数会自动调用自定义成员的默认构造。

10.析构函数

10.1概念

析构函数:与构造函数功能相反,析构函数不是完成对象的销毁,局部对象销毁工作是由编译器完成的。而对象在销毁时会自动调用析构函数,完成类的一些资源清理工作。不是销毁对象或者变量。

10.2特征

  1. 析构函数名是在类名前加上字符 ~。
  2. 无参数无返回值。
  3. 一个类有且只有一个析构函数。
  4. 对象销毁的时候,编译器自动调用析构,用来进行资源的清理。
  5. 不显式定义析构,编译器会自动生成默认的析构函数
  6. 析构函数自动调用自定义成员的析构函数,完成自定义成员的资源清理
typedef int DataType;
class SeqList
{
public :
 SeqList (int capacity = 10)
 {
 _pData = (DataType*)malloc(capacity * sizeof(DataType));
 assert(_pData);

 _size = 0;
 _capacity = capacity;
 }

 ~SeqList()
 {
 if (_pData)
 {
 free(_pData ); // 释放堆上的空间
 _pData = NULL; // 将指针置为空
 _capacity = 0;
 _size = 0;
 }
 }

private :
 int* _pData ;
 size_t _size;
 size_t _capacity;
};

11.拷贝构造函数

11.1概念

构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类类型对象创建新对象时由编译器自动调用。
例如:

Date d(2020, 2, 3);
	//调用拷贝构造,创建copy对象,内容和d完全相同
	Date copy(d);

调用拷贝构造,创建copy对象,内容和d完全相同

11.2 特征

  1. 拷贝构造函数是构造函数的一个重载形式。
  2. 拷贝构造函数的参数只有一个且必须使用引用传参,使用传值方式会引发无穷递归调用。
  3. 若未显示定义,系统生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝我们叫做浅拷贝,或者值拷贝
  4. 有资源的类,必须显式定义拷贝构造
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值