类和对象——上篇
1.类和对象的初步认识
C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。
C++是基于面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成。
可以粗劣的将类理解为一张设计图,而通过这张设计图设计出的建筑就可以称为对象。
struct与class的区别:
解答:C++需要兼容C语言,所以C++中struct可以当成结构体去使用。另外C++中struct还可以用来定义类。
和class是定义类是一样的,区别是struct的成员默认访问方式是public,class是struct的成员默认访问方式
是private。
封装
封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行
交互。
类的结构体内存对齐
只计算结构体中成员变量的大小,而对于空类则系统默认给的大小为1个字节。
面试题
-
结构体怎么对齐? 为什么要进行内存对齐
解答:(以空间换时间)
(1):平台原因(移植原因): 不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址
处取某些特定类型的数据,否则抛出硬件异常。
(2)性能原因: 数据结构(尤其是栈)应该尽可能地在自然边界上对齐。 原因在于,为了访问未对齐的内存,处理
器需要作两次内存访问;而对齐的内存访问仅需要一次访问。 -
如何让结构体按照指定的对齐参数进行对齐
解答:使用pragma pack 宏来修改默认对齐数
#include<stdio.h>
#include<windows.h>
#pragma pack(1)
struct S1
{
int i;
char j;
double k;
};
#pragma pack()
int main()
{
printf("%d\n", sizeof(struct S1));
system("pause");
return 0;
}
- 如何知道结构体中某个成员相对于结构体起始位置的偏移量
#define offsetof(s,m) (size_t)&(((s *)0)->m)
1.(s*)0地址强制 “转换” 为 s结构类型的指针;
2.((s*)0)->m访问结构体中m中的成员
3.&((s*)0)->m取出结构中m成员的地址
4.size_t转换为整形数据。
struct A
{
int a;
short b;
}v;
cout << Offsetof(struct A, b) << endl;
- 什么是大小端?如何测试某台机器是大端还是小端,有没有遇到过要考虑大小端的场景
添加链接描述
@在不同类型的机器之间通过网络传送二进制数据时。一个常见的问题是当小端法机器产生的数据被发送到大端法机器或者反之时,接受程序会发现,字(word)里的字节(byte)成了反序的。为了避免这类问题,网络应用程序的代码编写必须遵守已建立的关于字节顺序的规则,以确保发送方机器将它的内部表示转换成网络标准,而接受方机器则将网络标准转换为它的内部标准。
@ 当阅读表示整数的字节序列时。这通常发生在检查机器级程序时,e.g.:反汇编得到的一条指令:
80483bd: 01 05 64 94 04 08 add %eax, 0x8049464
@ 当编写规避正常的类型系统的程序时。
为什么会有大小端模式之分呢?
这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着
一个字节,一个字节为8bit。但是在C语言中除了8bit的char之外,还有16bit的short型,32bit的long型(要
看具体的编译器),另外,对于位数大于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于
一个字节,那么必然存在着一个如果将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。
this指针
什么是this指针?
当我们进入一个房子之后,可以看见房子里的电视、灯、花草等,但是看不到房子的全貌。对于一个类的实例来说,
你可以看到它的成员函数、成员变量,但是实例本身呢?this是一个指针,它时时刻刻指向这个实例
具体说明:
在建立对象时,系统会为每一个对象分配独立的存储空间,也就是给每个对象中的数据成员都分配
有自己独立的存储空间。如果对同一个类定义多个对象,则有多个同样大小的空间存放对象中的数据成员,
但对于成员函数来说,一个函数的代码段在内存中只有一份。也就是说,同一个类中的不同对象在调用自己的成员函数时,
其实它们调用的是同一段函数代码。
那么,当一个对象调用自己的成员函数时,如何保证成员函数中对数据成员的处理是针对自己的数据成员
而不是其他对象的数据成员呢?
答案就是:this指针
void printf(Date* const this);
每一个非静态成员函数中都包含一个this指针
this指针特性:
1.this指针的类型:类型* const
2.this指针并不是对象本身的一部分,不影响sizeof的结果
3.this的作用域在类”成员函数”的内部
4.this指针是”类成员函数”的第一个默认隐含参数,编译器自动维护
5.传递,类编写者不能显式传递
6.只有在类的非静态成员函数中才可以使用this指针,其它任何函数都不可以
7.存储类型:this指针是由编译器生成的,当类的非静态成员函数的参数个数一定时
this指针存储在ecx寄存器中,调用——thiscall约定。若该函数参数个数未定(可变参数)存放在栈中
this指针能否为空?
class Date
{
public:
void PrintA()
{
cout << _a << endl;
}
void Show()
{
cout << "show()" << endl;
}
private:
int _a;
};
int main()
{
Date* p = NULL;
p->PrintA();//对this指针进行了解引用
p->Show();//未对this指针进行解引用
system("pause");
return 0;
}
print函数与show函数均可以通过编译,但print函数在函数体中对this指针进行了解引用所以程序奔溃,show()函数中虽然传了一个空指针但是并没有对他进行解引用操作,所以程序可以运行。