一、类的定义
1.类定义格式
(1)C++中class和struct是定义类的关键字,其后接着“{};”,要注意分号不可以省略。
(2){}中的内容称为类的成员,其中的变量称为类的属性或成员变量,类中的函数称为类的方法或成员函数。
(3)C++中兼容C语言中struct的用法。
(4)定义在类内的成员函数默认为inline。
class Date
{
public:
void Init(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
void Print()
{
cout << _year << '/' << _month << '/' << _day << endl;
}
private:
// 为了区分成员变量,⼀般习惯上成员变量
// 会加⼀个特殊标识,如_ 或者 m开头
int _year; // year_ m_year
int _month;
int _day;
};
2.访问限定符
(1) C++⼀种实现封装的方式,用类将对象的属性与方法结合在⼀块,让对象更加完善,通过访问权限选择性的将其接口提供给外部的用户使用。
(2)有三种访问限定符,public,protected,private。
(3) 其中public修饰的成员在类外可以直接被访问;protected和private修饰的成员在类外不能 直接被访。
(4)访问权限作用域结束是直到下一个访问限定符出现为止,如果没有下一个访问限定符,那么到“}”即结束。
(5)class定义成员没有被访问限定符修饰时默认为private,struct默认为public。
3.类域
(1)类定义了一个新的作用域,类的所有成员都在作用域里,因而在类外使用定义成员就可以用::来指定类域。
class Stack
{
public:
// 成员函数
void Init(int n = 4);
private:
// 成员变量
int* array;
size_t capacity;
size_t top;
};
// 声明和定义分离,需要指定类域
void Stack::Init(int n)
{
array = (int*)malloc(sizeof(int) * n);
if (nullptr == array)
{
perror("malloc申请空间失败");
return;
}
capacity = n;
top = 0;
}
二、实例化
1.实例化概念
(1)用类类型在物理内存中创建对象的过程,称为类实例化出对象。
(2)类是对象用的⼀种抽象描述,是⼀个模型⼀样的东西,限定了类有哪些成员变量,这些成员变量只是声明,没有分配空间,用类实例化出对象时,才会分配空间。
(3)一个类可以实化出多个对象。
2.对象大小
(1)C++中实例化后的类成员变量是会分配独立空间的,那么成员函数会不会呢?我们来仔细想想如果每个实例化后的变量函数都单独分配空间会不会太浪费空间了,毕竟函数都一样,只是参数不同。再次就是函数被编译后只是一段指令,对象里没法储存,如果硬要储存那只能是用指针来存储,但函数指针只是一个地址,只要找到地址就不需要存储,因此成员函数不会单独分配空间。
(2)内存对齐规则
当第一个成员在与结构体偏移量为0的地址处,其他成员变量要对齐要某个数字(就是对齐数)的整数倍的地址处。
对齐数一般是编译器默认的一个对齐数与成员变量大小的较小值。就是编译器的默认对齐参数与所有变量类型的最大值取小。
如果嵌套了结构体,则嵌套的结构体对齐到自己的最大对齐数的整数倍。
#include<iostream>
using namespace std;
// 计算⼀下A/B/C实例化的对象是多⼤?
class A
{
public:
void Print()
{
cout << _ch << endl;
}
private:
char _ch;
int _i;
};
class B
{
public:
void Print()
{
//...
}
};
class C
{};
int main()
{
A a;
B b;
C c;
cout << sizeof(a) << endl;
cout << sizeof(b) << endl;
cout << sizeof(c) << endl;
return 0;
}
这里为什么后面两个类里没有成员变量却有占用空间呢?这就是为了表示它们存在过,这里给一字节空间纯粹就是为了占位标识对象。
三、this指针
1.就如下面Date类中有Init与Print两个成员函数,函数体中没有关于不同对象的区分,那当d1调用 Init和Print函数时,该函数是如何知道应该访问的是d1对象还是d2对象呢?那么这里就要看到 C++给了⼀个隐含的this指针解决这里的问题。
2.编译器编译后,类的成员函数默认都会在形参第⼀个位置,增加⼀个当前类类型的指针,叫做this指针。比如Date类的Init的真实原型为, void Init(Date* const this, int year,int month, int day)。
3.类的成员函数中访问成员变量,本质都是通过this指针访问的,如Init函数中给_year赋值, this-
>_year = year;
4.C++规定不能在实参和形参的位置显示的写this指针(编译时编译器会处理),但是可以在函数体内显示使用this指针。
#include<iostream>
using namespace std;
class Date
{
public:
// void Init(Date* const this, int year, int month, int day)
void Init(int year, int month, int day)
{
// 编译报错:error C2106: “=”: 左操作数必须为左值
// this = nullptr;
// this->_year = year;
_year = year;
this->_month = month;
this->_day = day;
}
void Print()
{
cout << _year << "/" << _month << "/" << _day << endl;
}
private:
// 这⾥只是声明,没有开空间
int _year;
int _month;
int _day;
};
int main()
{
// Date类实例化出对象d1和d2
Date d1;
Date d2;
// d1.Init(&d1, 2024, 5, 28);
d1.Init(2024, 5, 28);
d1.Print();
d2.Init(2024, 7, 20);
d2.Print();
return 0;
}