先来回顾一下结构体:
结构体是一些数据的集合,这些数据可以是不同类型,在C语言中结构体中不能定义函数,在C++中结构体可以定义函数。
结构体中有内存对齐问题,可以参考以前的文章:点击打开链接
但在C++中,结构体中有函数的定义更喜欢用类(class)来表示。
一、类的定义
两种方式:1)类的声明和定义全在类体中
2)类的声明在.h文件中,类的定义在.cpp文件中。
//声明和定义都在类体中
class A //A为类名
{
//类体:由函数和变量组成
public:
void FunTest() //类的方法/类的成员函数
{
cout << "This is FunTest" << endl;
}
private:
int a; //类的成员变量
};
int main()
{
A a;
a.FunTest();
return 0;
}
第二种:
//.h
class B
{
public:
void test();
private:
int _b;
};
//.cpp
#include "test.h"
void B::test() //此处要写返回值
{
cout << "This is Test!" << endl;
}
int main()
{
B b;
b.test();
return 0;
}
二、封装
说到类,就要说一下C++第一个特性:封装
1)封装:隐藏对象的属性和实现细节,仅对外公开接口和对象进行交互,将数据和操作数据的方法进行有机结合。
函数也是封装的一种形式,函数中的语句被封装在函数本身这个更大的实体中,被封装的实体隐藏了其实现细节,可以调用该函数但不能访问函数中的语句。
2)封装一般通过访问限定符实现:public(公有)、protected(保护)、private(私有)
说明:1.public成员可以在类外进行访问,protectrd和private在类外不能进行访问
2、作用域从该访问限定符出现的位置直到下一个访问限定符出现
3.class的默认访问权限是private,而struct为public
三、类的作用域
类定义了一种新的作用域--类域,类中的所有成员都必须在类域中。形参表和函数体处于类的作用域中。在类外定义成员,需要使用::作用域解析符指明成员处于哪一个类域中。在类的作用域外,只能通过对象或指针借助成员访问操作符->来访问类成员,跟在访问操作符后面的名字必须在类的作用域中。
成员变量在类中具有全局作用域。
int a = 20;
class Test
{
public:
void Seta(int a) //两个a均来自形参,就近原则
{
a = a;
}
void PrintA()
{
cout << "a=" << a << endl;
}
private:
int a = 10;
};
int main(void)
{
int a = 40;
Test t;
t.Seta(1);
t.PrintA(); //10
cout << a << endl; //40 先在函数作用域中找,找不到再去全局变量中找
Test *p = new Test; //通过指针访问类成员
p->PrintA(); //10
delete p;
return 0;
}
四、类的实例化
1.实例化
1)定义:用类类型创建对象的过程,称为类的实例化。
2)说明: 1>类只是一个模型一样的东西,限定了类中有哪些成员,定义出一个类并没有分配实际的内存空间来存储。
2>一个类可以实例化多个对象,实例化出的对象占用实际的物理空间来存储类中的成员变量
2、类的对象模型
看一段简单的代码:
class Test
{
public:
void FunTest()
{
cout <<_a << endl;
}
private:
int _a;
};
int main()
{
cout << sizeof(Test) << endl; //4
return 0;
}
其中类的大小为4,看一下内存
可以看出类的大小就是成员变量所占内存,类中的成员函数并没有占用内存。
class Test
{
public:
void FunTest()
{
cout <<_a << endl;
}
private:
char _a[20];
char _b[3];
int _c;
};
int main()
{
Test t;
cout << sizeof(t) << endl; //28
return 0;
}
从以上代码可以看出,类中存储方式也是遵循内存对齐的,和结构体一样。
class Empty
{
};
int main()
{
cout << sizeof(Empty) << endl; //1
return 0;
}
注意:空类的大小为1,不是0,
因为类的实例化是在内存中分配一块地址,每个实例在内存中都有独一无二的地址。所有,空类也会实例化,编译器给空类添加了隐含的一个字节,这样空类实例化后也会有自己的一个地址
内存对齐的好处:便于处理器进行内存访问,提高效率
五、this指针
我们发现在调用类的成员函数时,不需要传类的成员变量,也能对类的成员变量进行操作,可能是因为在类中有一个默认字节保存了一个指向成员变量的指针,但在求大小的时候,类的成员函数并没有占内存,排除了这种可能。另一种可能是类的成员变量是全局变量,但在使用之前并没有看见其声明,定义在使用之后,不符合全局变量的规则。但我们在看程序的反汇编时,发现了一个新的东西-->this指针。
C++类中成员函数有一个隐藏的指针,指向了调用该函数的对象本身。
this指针的特性:
1>类型:类类型 * const
2>this指针并不是对象本身的一部分,不影响sizeof的结果
3>this的作用域在类非静态成员函数的内部
4>this指针是类成员函数的第一个默认隐含参数,编译器自动维护传递。
5>只有在类的非静态成员函数中才可以使用this指针,其他函数都不可以。
_thiscall调用约定:是一种调用方式
1>_thiscall只能用在类的成员函数上
2>参数从右向左压栈
3>如果参数个数确定,this指针通过ecx传递给被调用者;如果参数不确定,this指针在所有参数被压栈后压入堆栈
4>参数个数不确定,调用者自主清理,否则函数自己清理。