前言
- 🚄 输入是学习的本质,输出是学习的手段。
- 🔖 分享每一次的学习,期待你我都有收获。
- 🎇 欢迎🔎关注👍点赞⭐️收藏✉评论,共同进步!
- 🌊 “要足够优秀,才能接住上天给的惊喜和机会”
- 💬 博主水平有限,如若有误,请多指正,万分感谢!
☁️类的引入
在C语言中,我们学习了struct,但是*C语言中的struct只能定义变量,无法定义函数。
C++中也可以使用struct,且C++中的struct是兼容C语言的struct,并对其延伸——在C++中,struct可以定义函数
struct student
{
void Print()
{
cout << "name:" << _name << endl;
cout << "num:" << _num << endl;
cout << "age:" << _age << endl;
}
char _name[20];
int _num;
int _age;
};
C++中,更喜欢用class来代替struct,称为类。
所谓的类封装,就好比DNF、剑网三中的一个个人物一般,他们都是被封装起来的,我们作为玩家、用户
官方当然不允许玩家拥有随意更改人物属性的权利,否则不就人人都是一刀99999,这样游戏的寿命顷刻间就会被消耗殆尽,我们只能进行一些官方允许我们进行的操作。
比如放技能,走路…而这些都可以理解为其本质是在使用类成员函数。
C++中,class与struct有何区别?
C++中,class与struct在功能上基本相同,class既能定义变量,也能定义函数,struct也是如此。
它们唯一的区别在于:class的默认访问权限为private,struct的默认访问权限为public.根据使用场景不同,有时需要选择性地去使用。但总的来说,class的默认权限有利于更好地体现封装性,因而更常使用。
☁️类的实例化
用类类型创建对象的过程,称为类的实例化
类是一个抽象的定义,只是一个像模型一样的东西,限定了有哪些成员,定义本身不会分配实际的内存空间。
就像一个房子的设计图,画的设计图本身不会占据实际的地理空间。我们通过图纸建造出来的房屋,
才会占用实际的空间。类的实例化就好比用设计图实际建造出来的房屋,具有实际的空间。
类的定义不会分配实际的内存空间,类的实例化才会分配到实际的内存空间
☁️类对象的大小
在C语言中,我们学会通过内存对齐的原则去计算结构体的大小,类对象的大小,也是通过内存对齐计算大小的。
而计算大小的前提是我们知道类对象中有哪些成员。
我们看这样一段代码
class Student
{
void Print()
{
cout << "name:" << _name << endl;
cout << "num:" << _num << endl;
cout << "age:" << _age << endl;
}
char _name[20];
int _num;
int _age;
};
int main()
{
Student st;
int sz = sizeof(st);
cout << "sz = " << sz << endl;
return 0;
}
如果我们先不看成员函数,依据内存对齐的方式计算类对象的大小,会算出 sz =28。
运行结果与我们计算的一致,说明我们的假设成立,编译器是否也和我们一样,
不把成员函数当做类对象的一部分?
有这么两个类对象,很显然,它们的成员变量并不相同,但是当他们调用Print函数的时候,函数的定义是一模一样的。
如果每个对象都将这样的函数纳入对象本身,则一个对象需要额外分配一个空间给Print函数,如果有100个、
1000个对象呢?那么我们是不是还要额外分配这么多个空间给Print函数,但是每个Print函数的定义都是一样的,
这就造成了一种不必要的浪费,如果我们将成员函数保存在一个公共代码区中,
无论你有多少个这样的对象,你需要调用成员函数,就拿着这个函数的地址来这里调用,而函数也就写这一个,不会造成无意义的重复。
因此,类对象中只包含成员变量,不包含成员函数。
分析一下这段代码的运行结果
// 类中既有成员变量,又有成员函数
class A1 {
public:
void f1() {}
private:
int _a;
};
// 类中仅有成员函数
class A2 {
public:
void f2() {}
};
// 类中什么都没有---空类
class A3
{};
int main()
{
A1 a1;
A2 a2;
A3 a3;
int sz_a1 = sizeof(a1);
int sz_a2= sizeof(a2);
int sz_a3 = sizeof(a3);
cout << "sz_a1 = " << sz_a1 << endl;
cout << "sz_a2 = " << sz_a2 << endl;
cout << "sz_a3 = " << sz_a3 << endl;
return 0;
}
- a1的大小是4。
既然对象中不包含成员函数,那么a2和a3的大小就应该是一样的,先看看运行结果
既然对象里什么都没有,为什么计算出来会有一个字节?
先来思考这样一个问题:如果我这样定义对象
//注意:A3是空类
A3 t1;
A3 t2;
那编译器凭什么区分t1和t2,知道这是两个对象,而不是同一个对象?他们都是空类的对象,对象中都没有成员变量。但是,在内存中,不同的对象它们的地址肯定是不同的,给4个字节的地址用来区分两个空对象,显然有点得不偿失,因此编译器给了1个字节给空对象,用来占位,表示它们在这里存在过,借此对它们进行区分。