系列文章目录
文章目录
前言
C++作为一门面向对象的编程语言,面向对象有三大特性:封装,继承,多态,类就可以很好地体现出封装的特点,这篇文章,我将梳理讲解,我学习到的类和对象知识
正文
一、类的定义
1.类定义的格式
C++引入了class关键字来定义类,格式和我们定义结构体类似,比如我们定义一个Stack类
cpp
class Stack {
};
类体中内容称为类的成员:类中的变量称为类的属性或成员变量; 类中的函数称为类的⽅法或者成员函数
cpp
class Stack {
//成员函数
void Init();
void Push();
//成员变量
int* arr;
int top;
int capacity;
};
- C++中
struct也可以定义类,C++兼容C中struct的⽤法,同时struct升级成了类,明显的变化是struct中可以定义函数,⼀般情况下我们还是推荐⽤class定义类 - 定义在类⾯的成员函数默认为
inline
2.访问限定符
C++⼀种实现封装的⽅式,⽤类将对象的属性与⽅法结合在⼀块,让对象更加完善,通过访问权限选择性的将其接⼝提供给外部的⽤户使⽤
访问限定符有三个:public,protect,private
访问权限作⽤域从该访问限定符出现的位置开始直到下一个访问限定符出现时为⽌,如果后⾯没有访问限定符,作⽤域就到 }即类结束
public修饰的成员在类外可以直接被访问 ;protected和private修饰的成员在类外不能直接被访问 ,protected和private是⼀样的,以后继承才能体现出它们的区别
class定义成员没有被访问限定符修饰时默认为private,struct默认为public
cpp
class Stack {
public:
//成员函数
void Init();
void push();
//成员变量
int* arr;
int top;
int capacity;
};
int main()
{
Stack st;
st.top;
}
我们可以把类当作一个自定义类型,st就是我们这个类实例化出来的对象,它里面的成员调用方式和结构体差不多

这里可以看到,我们可以访问top
但是如果我们把它用private修饰
cpp
class Stack {
public:
//成员函数
void Init();
void push();
private:
//成员变量
int* arr;
int top;
int capacity;
};
int main()
{
stack st;
st.top;
}
就会报错

所以,⼀般成员变量都会被限制为private/protected,需要给别⼈使⽤的成员函数会放为public
3.类域
我们说C++有四个域,类域就是其中之一
类定义了⼀个新的作⽤域,类的所有成员都在类的作⽤域中,在类体外定义成员时,需要使⽤ :: 作⽤域操作符指明成员属于哪个类域
类也是支持声明和定义分离的,其实主要是类中的成员函数的分离

如果我们直接分离,在定义的时候,就会找不到成员变量
所以这时候我们需要指定类域

二、类的实例化
1.实例化概念
⽤类类型在物理内存中创建对象的过程,称为类实例化出对象
假如我们有一个栈类
cpp
class Stack {
public:
//成员函数
void Init();
void push();
private:
//成员变量
int* arr;
int top;
int capacity;
};
cpp
Stack st;
此时我们就实例化出了一个栈对象,名字是st
- 类是对象进⾏⼀种抽象描述,是⼀个
模型⼀样的东西,限定了类有哪些成员变量,这些成员变量只是声明,没有分配空间,⽤类实例化出对象时,才会分配空间 - ⼀个类可以实例化出
多个对象,实例化出的对象 占⽤实际的物理空间,存储类成员变量
类就像一个房子的蓝图,实例化就是照着图纸建起了房子

2.对象的大小
那我们实例化出了一个对象,它的大小的是多少呢?
其实类的大小计算规则,和结构体一样,都需要遵循内存对齐:
• 第⼀个成员在与结构体偏移量为0的地址处
• 其他成员变量要对⻬到某个数字(对⻬数)的整数倍的地址处
• 注意:对⻬数 = 编译器默认的⼀个对⻬数 与 该成员⼤⼩的较⼩值
• VS中默认的对⻬数为8
• 结构体总⼤⼩为:最⼤对⻬数(所有变量类型最⼤者与默认对⻬参数取最⼩)的整数倍
• 如果嵌套了结构体的情况,嵌套的结构体对⻬到⾃⼰的最⼤对⻬数的整数倍处,结构体的整体⼤⼩就是所有最⼤对⻬数(含嵌套结构体的对⻬数)的整数倍
那么问题来了,结构体里面没有函数,但是类里面有,那么函数要不要算在类的大小呢?
cpp
#include <iostream>
using namespace std;
class Stack {
public:
//成员函数
void Init();
void push();
private:
//成员变量
int* arr;
int top;
int capacity;
};
int main()
{
Stack st;
cout << sizeof(Stack) << endl;
cout << sizeof(st) << endl;
}
我们可以看看

可以发现,没有算上函数的大小
其实我们的函数,会单独把地址放到一个共区域,这样每个类需要的时候,去call这个地址就行了

我们再来看看
cpp
#include <iostream>
using namespace std;
class Stack {};
int main()
{
cout << sizeof(Stack) << endl;
}

对于一个空类,它也会有一个字节
这⾥给1字节,纯粹是为了占位标识对象存在
三、this指针
1.概念和定义
我们先来看这段代码
cpp
#include<iostream>
using namespace std;
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:
int _year;
int _month;
int _day;
};
int main()
{
//实例化
Date d1;
Date d2;
//初始化
d1.Init(2025, 1, 1);
d2.Init(2025, 2, 2);
d1.Print();
d2.Print();
return 0;
}

从结果的角度看上去没有问题,但是为什么我们Init函数可以区分,我们传递的参数,该给那个对象的成员呢,明明大家都是在公共区域去call函数的
这是因为这里有个隐藏的this指针
编译器编译后,类的成员函数默认都会在形参第⼀个位置,增加⼀个当前类类型的指针,叫做this指针
其实Init函数,真实的样子是这样的
cpp
void Init(Data* const this,int year, int month, int day)
//Data* const 保证this本身不被修改,指向内容可以修改
类的成员函数中访问成员变量,本质都是通过this指针访问的
所以这段代码,本质上是这样的
cpp
void Init(int year, int month, int day)
{
this->_year = year;
this->_month = month;
this->_day = day;
}
C++规定不能在实参和形参的位置显示的写this指针(编译时编译器会处理),但是可以在函数体内显示使⽤this指针
2.练习
下面我们来看两道题目
1.下⾯程序编译运⾏结果是()
A、编译报错 B、运⾏崩溃 C、正常运⾏
cpp
#include<iostream>
using namespace std;
class A
{
public:
void Print()
{
cout << "A::Print()" << endl;
}
private:
int _a;
};
int main()
{
A* p = nullptr;
p->Print();
return 0;
}
2.下⾯程序编译运⾏结果是()
A、编译报错 B、运⾏崩溃 C、正常运⾏
cpp
#include<iostream>
using namespace std;
class A
{
public:
void Print()
{
cout << "A::Print()" << endl;
cout << _a << endl;
}
private:
int _a;
};
int main()
{
A* p = nullptr;
p->Print();
return 0;
}
首先,我们排除A,因为语法没有问题 ,所以不会编译错误,顶多可能对空指针解引用了,但这也是运行错误
那么这两道就在于,一个Print函数访问了成员变量_a,一个没有访问
关键在于我们对于 p->Print();的理解,其实这句代码,编译器在转化为指令,就是去call我们的Print函数,p->仅仅是在给这个函数传递this指针这个参数
因为我们函数地址根本不存在类空间中,所以不涉及p的解引用,所以这里哪怕是(*p).Print();也是一样,不存在对空指针解引用
当然我们从汇编角度,也可以看出来

但是第二道题目访问_a就需要对this指针解引用了,所以1.C 2.B
3. this指针存在内存哪个区域的 ()
A. 栈 B.堆 C.静态区 D.常量区 E.对象⾥⾯
这里因为this指针,其实相当于是个函数的形参,所以直接A,秒了
总结
以上就是我对类和对象第一部分内容的梳理,对于类的定义,实例化,包括this指针,我们要理解深刻,不能只看表象,下面我还会更加深入的去讲解类和对象
如果你有什么问题或者建议 欢迎评论,感谢大家的支持