解答:C++需要兼容C语言,所以C++中struct可以当成结构体去使用。另外C++中struct还可以用来定义类。 和class是定义类是一样的,区别是struct的成员默认访问方式是public,class是struct的成员默认访问方式 是private。
解答:
封装:将数据和操作数据的方法进行有机的结合,隐藏对象的属性的实现细节,仅对外公开接口和对象 进行交互
封装的本质是一种管理:兵马俑的例子
解答:
1.第一个成员与结构体的偏移量是0
2.其他成员要对齐到对齐数的整数倍数的地址处
(对齐数vs中默认为8,gcc中默认为4,取默认对齐数和变量数据类型大小的较小值作为对齐数)
3.结构体的总大小为:最大对齐数的整数倍
4.如果嵌套了结构体,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的总大小就是所有最大对齐数(含嵌套的结构体)的整数倍处
为什么进行对齐?
1.平台移植原因:不是所有的硬件平台都能随意的访问任意地址上的任意数据的,某些硬件只能在某些地址处取某些特定类型的数据,否则抛出硬件异常
2.性能原因:数据结构(尤其是栈)应该尽可能的在自然边界上对齐,原因在于,为了访问未对齐的内存,处理器需要作两次访问,而对齐的内存访问仅需要一次
如何让结构体按照指定的大小进行对齐
1.使用(#pragma pack())
2.在编译器中自行设置
如何知道结构体中的某个成员相对于结构体起始位置的偏移量?
printf("%d\n",offsetof(A,c));用offsetof这个宏去求结构体中成员在结构体中的偏移量
什么是大小端?如何测试一台机器是大端还是小端,有没有遇到过需要考虑大小端的场景?
小端:低地址存低位;
大端:低地址存高位;
vs2013中是小端存储的
使用共用体测试大小端
#include
using namespace std;
int sys() {
union un
{
char a;
int b;
}un;
un.b = 1;
return un.a;
}
int main() {
int ret = sys();
if (1 == ret) {
cout << "当前机器为小端存储" << endl;
}
else
cout << "当前机器为大端存储" << endl;
cout<<"hello....."<<endl;
system("pause");
return 0;
}
利用指针方法
int sys() {
int a = 1;
char* p = (char*)&a;
if (*p == 1)
cout << "小端" << endl;
else
cout << "大端" << endl;
}
在套接字编程时需要考虑大小端的问题
this指针存在哪里?
this指针本质上其实是一个成员函数的形参,是对象调用成员函数时,将对象地址最为实参传递给this形参的.所以对象中不存储this指针
this指针是成员函数第一个隐含的指针形参,一般情况下是由编译器通过ecx寄存器自动传递的,不需要用户传递
this指针可以为空吗?
可以为空,当我们在调用函数的时候,如果函数内部并不需要使用到this,也就是不需要通过this指向当前对象并对其进行操作时才可以为空(当我们在其中什么都不放或者在里面随便打印一个字符串),如果调用的函数需要指向当前对象,并进行操作,则会发生错误(空指针引用)就跟C中一样不能进行空指针的引用.
1.malloc分配一块内存空间,但他不能初始化内存空间,返回值为void*,C和C++允许强制类型转换
2.calloc分配一块内存空间并将该空间中值初始化为0;
3.realloc重新分配空间大小(缩小或者扩大),一般在已有的空间后面开辟内存,如果大小不够则在堆上寻找足够大小的neicun,并将老的空间返回到堆上
malloc/free和new/delete的共同点是:都是从堆上开辟内存空间,并且需要用户手动进行释放,
不同点:
1.malloc和free是库函数,new和delete是操作符
2.malloc申请的空间不会初始化,new可以进行初始化
3.malloc申请空间时,需要通过手动计算空间大小并传递,new只需在后面跟上空间类型即可
4.malloc的返回值是一个void*,在使用的时候必须进行强制类型转换,new不需要,因为new后跟的是空间类型
5.malloc申请空间失败时会返回一个NULL,因此使用的时候必须判空,new不需要,但是new需要捕获异常
6.申请自定义类型对象时,malloc/free只会开辟内存空间,不会调用构造函数和析构函数,而new在申请空间后会调用构造函数完成对对象的初始化,delete在释放空间前会调用析构函数完成空间中资源的清理
对比 | vector | list |
---|---|---|
底 层 架 构 |
动态顺序表一段连续的空间 | 带头结点的双向循环链表 |
随 机 访 问 |
支持随机访问访问效率为O(1) | 不支持随机访问访问效率为O(n) |
插 入 和 删 除 |
任意位置插入和删除效率低 需要搬动元素时间复杂度为O(n) 增容:开辟新空间拷贝元素释放旧空间 导致效率更低 |
任意位置插入和删除效率高 不需要搬动元素,时间复杂度为O(1) |
空 间 利 用 率 |
底层为连续空间不容易造成内存碎片 空间利用率高缓存利用率高 |
底层结点动态开辟,小结点 容易造成内存碎片,空间利用率低 缓存利用率低 |
迭 代 器 |
原生态指针 | 对原生态指针<结点指针>进行封装 |
迭 代 器 失 效 |
在插入元素时要给所有元素重新赋值,因为插入 元素可能会导致重新扩容,致使原来迭代器失效,删 除时,当前迭代器需要重新赋值否则失效 |
插入元素不会导致迭代器失效, 删除元素时只会导致当前迭代器 失效,其他迭代器不受影响 |
使 用 场 景 |
需要高效存储,支持随机访问,不关心插入删除效率 | 大量插入删除,不关心随机访问 |
stack是一种先进后出的特殊线性结构,因此只要具有push_back()和pop_back()操作的线性结构,都可以作为stack的底层容器,比如vector和list都可以;queue是先进先出的特殊线性数据结构,只要具有
push_back()和pop_back()操作的线性结构,都可以作为queue的底层容器,比如list.但在STL中对stack和queue默认选择deque作为其底层容器,主要是因为:
1.stack和queue不需要遍历(因此stack和queue没有迭代器),只需要在固定的一端或者两端进行操作.
2.在stack中元素增长时,deque比vector的效率高,queue中的元素增长时,deque不仅效率高,而且内存使用率高.