目录
3.如何让结构体按照指定的对齐参数对齐?能否按照3、4、5任意字节对齐?
4.什么是大小端?如何判断机器是大端还是小端?有没有遇到要考虑大小端的场景
1. 面向过程和面向对象初步认识
C语言是面向过程的,分析出求解问题的步骤,通过函数调用解决
C++是面向对象的,关注的是对象,把事情拆分成不同的对象,靠对象之间的交互完成。
2.类的引入
C语言结构体只能定义变量,而C++不仅可以定义变量,还可以定义函数。
3.类的定义
class classname
{
//类的成员变量和成员函数
};
class是类的关键字,classname是类名,{}内是类的主体
类体:在类中定义的变量叫做类的属性或者成员变量,定义的函数叫做类的方法或成员函数
3.1类的两种定义方法
1. 声明和定义全部放在类体中,要注意的是,成员函数可能会被当做内联函数处理
2.类声明放在.h文件中,成员函数定义放在.cpp文件中
4.类的访问限定符和封装
4.1 访问限定符
C++实现封装的方式:用类将对象的属性和方法结合在一块,让对象更加完善,通过访问权限选择性的提供接口以供外部用户使用。
public(公用) |
protected(保护) |
private(私有) |
访问限定符说明:
1.public修饰的成员可以在类外直接被访问
2.protected和private修饰的成员不可在类外直接被访问
3.访问权限作用域从该访问限定符开始直到下一个访问限定符出现为止。
4.如果后面没有访问限定符,那么就到 } 为止。
5.class的访问限定符默认为private,struct的访问限定符默认为public(因为要兼容C).
注意:访问限定符只在编译的时候有用,在数据映射到内存时,没有任何访问限定符的区别。
4.2 封装
面向对象的三大特性:封装、继承、多态
封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅通过公布对外接口来和对象进行交互。
在C++语言中实现封装,可以通过类将数据以及操作数据的方法进行有机结合,通过访问权限来隐藏对象内部实现细节,控制哪些方法可以在类外直接被使用。
5 类的作用域
类定义了一个新的作用域,类的所有成员都在这个类的作用域中,在类外定义成员时,需要使用::作用域操作符指明成员属于哪个类。
class Date
{
public:
void PrintDate();
private:
int _year;
};
void Date::PrintDate()//在类外定义成员函数时,需要使用::来指明属于哪个类
{
cout << _year << endl;
}
6.类的实例化
用类类型创造对象的过程,叫做类的实例化
1.类是对对象进行描述的,是一个模型一样的东西,限定了类有哪些成员,定义一个类并没有分配实际的内存空间的存储它。
2.一个类可以实例化出多个对象,实例化出的对象各自占用实际的物理空间,存储成员变量。
int main()
{
Date._year=2022;// error C2059: 语法错误:“.”
return 0;
}
Date类是没有空间的,只有Date实例化的对象才有实际的年份。
3.打个比方,类实例化对象就像使用建筑设计图建造一个房子,类就像是设计图,只设计出需要什么东西,但是并没有实际的建筑存在。
7.类对象模型
7.1 如何计算类对象的大小
class Date
{
public:
void PrintDate(int day)
{
cout<<_day<<endl;
}
private:
int _day;
};
用类实例化一个对象后,有成员函数和成员变量,那怎么知道这个对象的大小呢?
7.2 类对象的存储方式猜测
1.类对象中存储类中的各个成员。
缺陷:每个对象中成员变量是不同的,但是调用的是同一个函数,实例化多个对象时保存多份代码,浪费空间
2.类对象中存储成员变量,成员函数代码保存一份,在对象中存放代码的地址。
3.只保存成员变量,成员函数代码放在公共代码区。
猜测了三种,那实际上计算机是按照什么方式存储的呢?
class A1//类中只有成员变量和成员函数
{
public:
void PrintA1()
{
;
}
private:
int _a;
};
class A2//类中只有成员变量
{
private:
int _a;
};
class A3//类中只有什么都没有
{
};
实验可以得知,类中只存储成员变量,一个类的大小为所有成员变量的总和,当然这其中要注意内存对齐。
注意:在类为空时,计算机给出一个字节的空间来标识它。
7.3 结构体内存对齐规则
1.第一个成员在结构体偏移量为0的地址处
2.其他成员变量对齐到对齐数的整数倍的偏移处。
注意:对齐数为默认对齐数跟变量本身字节大小中较小的那个
3.结构体的总大小为:最大对齐数(所有变量类型最大者和默认对齐数中取最小)的整数倍
4.如果嵌套了结构体,嵌套的结构体对齐到自己最大对齐数的整数倍,结构体的整体大小就是所有对齐数(含嵌套结构体的对齐数)中最大的对齐数的整数倍
8.this指针
8.1 this 指针的引入
先来定义一个演示用的日期类
class Date
{
public:
void Init(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
void PrintDate()
{
cout << "print" << endl;
}
private:
int _day;
int _month;
int _year;
};
int main()
{
Date d1;
Date d2;
d1.Init(2022,1,1);
d2.Init(1,1,1);
d1.PrintDate();
d2.PrintDate();
return 0;
}
对于上面的类可以发现:
在类中有两个成员函数Init和PrintDate,函数体中没有关于不同对象的区分。那么在d1调用Init时,该函数是如何知道要设置的是d1的成员变量而不是d2的呢?
C++通过引入this指针解决该类问题。即:C++为每个"非静态成员函数"增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用函数的对象)。函数体中所有"成员变量"的操作都是通过该指针去操作的。只不过由编译器来完成,用户不可见。
8.2 this指针特性
1.this指针类型为 类类型* const,即成员函数中,this指针不可被赋值。
2.只能在“成员函数”内部使用
3.this指针实际上是形参,对象调用成员函数时将函数的地址作为实参传递给this指针做形参,所以,对象中不存储this指针。
4.this指针是”成员函数“的第一个隐含的指针形参,一般情况下由编译器使用寄存器ecx自动传递,不需要用户传递。
几个小问题
1. C++中struct和class的区别是什么?
C++中struct和class都是类,可以定义成员变量和成员函数。但struct默认访问限定符是public(因为需要兼容C),class默认访问限定符则是private.
2.结构体如何对齐?
结构体的第一个成员变量对齐到结构体偏移量为0的地址处
其他成员对齐到 对齐数(默认对齐数和自身类型字节大小中较小的数)整数倍的地址处。
结构体整体大小是最大对齐数和默认对齐数中较小的数的整数倍
如果有嵌套的结构体,嵌套的结构体对齐到其最大对齐数的整数倍处
结构体的总大小(含嵌套)对齐到所有对齐数中最大的数的整数倍处
3.如何让结构体按照指定的对齐参数对齐?能否按照3、4、5任意字节对齐?
通过设置默认对齐数:
#pragma pick(push,3)//把原来的对齐方式压栈,并设置新的对齐方式按3字节对齐 #pragma pick(pop)//恢复原来的对齐方式 #pragma pick(push,4) #pragma pick(pop) #pragma pick(push,5) #pragma pick(pop)
4.什么是大小端?如何判断机器是大端还是小端?有没有遇到要考虑大小端的场景
对于一个由两字节组成的16位整数,在内存中存储这两个字节有两种方式:
1.将低序字节存储在起始地址,这叫做小端(little-endian)字节序
2.将高序字节存储在起始地址,这叫做大端(big-endian)字节序
假设有一个int整型的数0x12345678,最低有效字节是0x78,最高有效字节是0x12。那么假设存储的地址从0x0004开始
小端字节序:
0x0007 0x0006 0x0005 0x0004 0x78 0x56 0x34 0x12
大端字节序
0x0007 0x0006 0x0005 0x0004 0x12 0x34 0x56 0x78
网络通信需要考虑大小端
5.this在哪里?
程序编译时会添加一个获取对象首地址的代码,并把获取的代码存入寄存器ecx中。
6.this指针可以为空吗?
this可以为空,但不推荐这样做。因为这样不能调用含有非静态成员的函数