文章目录
- [一、 类的定义与基本结构](#一、 类的定义与基本结构)
- 二、对象的实例化与内存模型
- 三、深入理解this指针
一、 类的定义与基本结构
1.1类定义格式(class和struct)
类的定义与C语言中的结构体定义格式类似,并且C++中兼容C所以,用struct也可以创建类
cpp
class 类名
{
成员变量
成员函数
};
C++中将变量和函数封装放到一起构成了类
- 成员变量
- 成员函数
小tips:为了区分普通变量和成员变量,我们一般在成员变量前加一个_来区分
cpp
class A
{
//成员函数
public:
void Init(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
void Print()
{
cout << _year << _month << _day;
}
//成员变量
private:
int _year;
int _month;
int _day;
};
习惯上我们将成员函数放在上,成员变量放在下创建
注意:
创建的类相当于C语言中的函数声明,没有对象这个实体,所以也没有开辟空间,后续创建了实体------对象才会开辟空间。
struct也可以创建类,但是和class相比略有差距
- C++中,struct无需再通过typedef来重命名,无需再带上struct直接使用结构体名就可以代表类型,C++兼容C所以即使写typedef也正确

- 不给定访问限定情况,class定义的类访问限定权限默认是private (私有),struct定义的类的访问限定权限默认public(公有)
1.2访问限定符
- public(公有)
- private(私有)
- protected(保护)
在目前阶段,private和protected的功能一致,就是在类外无权限访问,但是在类内可以随意访问,public则是在类内外都可以任意访问。
通常情况,我们只对外提供函数接口,所以成员变量一般都是private或者protected,成员函数为public
1.3类域
在C++入门基础中我们了解到,域分为函数局部域,全局域,命名空间域,类域四种 ,类的所有成员都在类域中,域外需要访问时,要使用 :: 域限定作用符
在类中函数声明和定义也可以分离,但是分离后在类外需要 :: 来访问
cpp
struct A
{
public:
//函数声明
void Init(int year, int month, int day);
void Print()
{
cout << _year << _month << _day;
}
private:
int _year;
int _month;
int _day;
};
//类外访问,域限定作用符访问
void A::Init(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
二、对象的实例化与内存模型
2.1实例化的概念
定义:
形象比喻: 类像是建造房子的图纸,对象就是按照图纸建造的房子,一张图纸可以建造许多房子
类是对象的模板,而对象是类的实例化
对象的创建和使用方式与结构体的使用方式完全一致,直接使用类型名创造对象,需要访问对象内的成员则使用成员访问运算符访问(. 和 ->(指针类型))
cpp
class A
{
public:
//成员函数
void Init(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
void Print()
{
cout << _year << "/" << _month << "/" << _day << endl;
}
private:
//成员变量
int _year;
int _month;
int _day;
};
int main()
{
A a;
a.Init(100, 20, 30);
a.Print();
return 0;
}
类的创建并不会为其分配内存空间,只有实例化对象时,才会有内存空间的分配
2.2对象大小的计算
我们说结构体的使用方法与类和对象的使用方法一致,那么存储对象的方式是不是也是异曲同工之妙呢?
想像一个场景,我们利用类实例化了100个对象,每个对象都是独立的数据空间,成员变量有所不同,所以这100个对象中的每一个成员变量都存储在自己的对象中,但是每个对象中的成员函数都是相同的,而且函数被编译后是一段指令,对象内无法存储,所以如果每个成员函数都分别存在自己的对象中,那么100个对象的内存大小是相当大的,函数的执行逻辑都是相同的,对象中的成员函数不存在对象内,而是只保存一份,代码指令保存在" 代码段 "中
内存对齐规则

cpp
class Hy
{
public:
void print()
{
cout << "print()" << endl;
}
private:
char _a;
int _b;
};

char类型值从地址偏移量为0的位置开始存放,char的大小为1小于vs默认对齐数,故占用1个字节位置,int类型值对齐数为4,对齐到最近的整数倍,即从偏移量为4的的位置开始存放,(中间三个字节依次填充)然后他的大小为4字节,整体加下来为8字节,是最大对齐数4的倍数,所以这个对象的大小为8字节
特殊情况:
cpp
class Hy
{
private:
void print()
{
cout<< "print()" << endl;
}
};
没有成员变量的对象大小为1,这个1纯粹是为了证明对象的存在。
三、深入理解this指针
3.1this指针的由来与作用
同一个类实例化出的对象中的成员函数是同一个,只会存储一份,调用函数时,他们是如何获取不同对象中的成员变量呢?
cpp
class Data
{
public:
void Init(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
void print()
{
cout << _year << "/" << _month << "/" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
两次调用成员函数print,对于编译器来说这是相同的一段指令,那么他是如何获得成员变量数据的呢?
在编译链接阶段,编译器会自动为成员函数形参部分提供ClassName* const this指针,这里为隐士传递,相当于在调用时自动传入了对象的地址,从而在函数的形参中接收到了函数的地址,进而隐式解引用获得成员变量数据。
3.2this指针的性质
cpp
void Init(/* Data* this */int year, int month, int day)
{
this->_year = year;
this->_month = month;
this->_day = day;
}
- 存储在栈区(作为函数形参传入)或者特定寄存器中(如ECX)
- 不能显式写在参数和形参中,但是可以写在函数定义内
下期预告:类和对象(中)---类的六大默认构造函数
