【C++】简单学——类和对象(上)
类和对象的关系
类 是 模板(比如“手机设计图”),对象 是 具体的东西(比如“你手里的iPhone”)
类
类的定义
C++中,struct和class都可以成员变量和成员函数放一块(属性和方法)
使用展示:
class Date
{
public:void Print(){cout << _year << "年" << _month << "月" << _day << "日" << endl;}
private:int _year;int _month;int _day;};
番外
类域
大括号就是域,和命名空间差不多,需要用宏观的角度来看域,如果不想冲突,就用大括号括起来,甚至是for循环里面的,大的域的东西可以在小的域里面去用,小的就不行,(有点像是内部类)
类的结构
1、类名
在 同一个作用域 内,类名不能重复,否则会导致 重定义错误。
2、访问限定符
访问限定符 | 类内部访问 | 派生类(子类)访问 | 类外部(对象)访问 | 主要用途 |
---|---|---|---|---|
public | ✅ 可访问 | ✅ 可访问 | ✅ 可访问 | 提供类的接口,允许外部直接访问 |
protected | ✅ 可访问 | ✅ 可访问 | ❌ 不可访问 | 允许子类继承和访问,但不对外公开 |
private | ✅ 可访问 | ❌ 不可访问 | ❌ 不可访问 | 封装类的内部实现细节,防止外部修改 |
- public修饰的成员在类外可以直接被访问
- protected和private修饰的成员在类外不能直接被访问(此处protected和private是类似的)
- 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止
- 如果后面没有访问限定符,作用域就到}即类结束。
- class的默认访问权限为private,struct为public(因为struct要兼容C)
3、成员变量的声明
下图用private标注的地方就是这个类的成员变量
问:但我们怎么确定他是声明而不是定义呢?
答:开空间了就是定义
目前这个位置的成员变量只是在类中,并没有实例化出具体的对象
(本来类就只是一个房屋图纸,既然没有真正去建房子,又怎么会占用空间呢?)
P.S. 定义不等于初始化,定义就是开空间,初不初始化才是下一步
对象
对象的实例化
//Date类的实例化int main()
{Date d1;return 0;
}
对象大小计算
遵循以下规则:
- 内存对齐
- 方法不占用空间
- 没有成员变量的类对象大小1byte
1、内存对齐
结构体/类对象:内存对齐规则
1.第一个成员在与结构体偏移量为0的地址处。
2.其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
注意:对齐数=编译器默认的一个对齐数与该成员大小的较小值。
VS中默认的对齐数为8
3.结构体总大小为:最大对齐数(所有变量类型最大者与默认对齐参数取最小)的整数倍。
4.如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整
体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
2、方法不占用空间
假设不知道方法是否占用空间
存储方案有两种:
1、一个对象里面同时存成员变量和成员函数的地址(不合理,因为一百个对象里面存的成员函数的都是一样的)
2、只存成员变量,成员函数就存在一个公共区域(代码区/代码段)
(调用的时候,在编译的时候就去找到了那个函数的地址,或者说没找到,就在链接的时候查符号表就找到了这个函数的地址)
因此方法是不会存储在对象中的
没有成员变量的类对象大小1byte
作用:占位,标识对象存在过
this指针
前情提要
class Date
{
public:void Print(){cout << _year << "年" << _month << "月" << _day << "日" << endl;}
private:int _year;int _month;int _day;
};int main()
{Date d1;Date d2;d1.Print();d2.Print();return 0;
}
在上面的代码中,d1和d2作为两个不同的对象访问了同一个函数
问:为什么不同的对象访问同一个函数的时候,明明没有传参,编译器是怎么识别是哪个对象去调用函数的?
答:每个成员函数默认第一个参数就是一个隐含的this指针
this指针的概念
this代表的是对象自己,将以上的代码翻译即可理解什么是this指针
class Date
{
public:void Print(Date* const this){cout << this->_year << "年" << this->_month << "月" << this->_day << "日" << endl;}
private:int _year;int _month;int _day;
};int main()
{Date d1;Date d2;d1.Print(&d1);d2.Print(&d2);return 0;
}
隐含的this指针让我们可以不用再自己传对象指针过去了
这个奇思妙想的前世今生:
//顺序表的初始化每次都要先传递一个结构体指针 void Init(ST * pst) {/...... }
祖师爷写C语言写烦了,传递这个结构体指针的事祖师爷交给了编译器来去做
this的特性
- 形参和实参的位置不能显示写this
- this自身是无法改变的,默认用const修饰this本身
- 函数的内部显示地用this
- this存储的位置是栈区(因为this是成员函数一个隐含的形参,形参就是在栈区的,有些编译器(比如VS)会存到寄存器中)
const在*之前修饰的是指向的内容不能被修改,在*之后修饰的是指向不能被修改