目录
- 前言
- 类的定义
- 类的访问限定符及封装
- 访问限定符
- 封装
- 类的大小
- 为什么需要内存对齐
- 为什么成员函数不占用类的内存?
- 为什么空类的大小是1个字节?
前言
今天是少年正式认识"对象"的第一天,虽然此"对象"非彼对象,但是少年也想好好的与你认识认识,所以少年在这里先跟你打个招呼。
我们都知道豹子、老虎、猫…都是猫科动物。这里我们用猫科动物来作为这些动物的类,而豹子、老虎、猫是这个类下的具体动物即对象。在生活中有了类与对象的概念我们就可以很简单描述一个复杂的事物。比如:王者荣耀是一个我方英雄与敌方英雄的塔防游戏。英雄是类,塔也是类,用了两个类就简单的描述了几百万人玩的游戏。试想一下假如没有类的概念你该怎么描述呢?
而在C++中为了更好的"表达"也引入了类与对象的概念(祖师爷666)。
类的定义
C++中使用关键字 class 来定义类, 其基本形式如下:
class className
{
// 类体:由成员函数和成员变量组成
}; // 一定要注意后面的分号
class为定义类的关键字,ClassName为类的名字,{}中为类的主体,注意类定义结束时后面分号不能省略。
类体中内容称为类的成员:类中的变量称为类的属性或成员变量; 类中的函数称为类的方法或者成员函数。
类的两种定义方式:
- 声明和定义全部放在类体中,需注意:成员函数如果在类中定义,编译器可能会将其当成内联函数处理。
class Hero
{
public:
//英雄的1技能
int func1()
{
return 0;
}
//英雄的2技能
int func2()
{
return 0;
}
//英雄的3技能
int func3()
{
return 0;
}
//英雄的4技能
int func4()
{
return 0;
}
private:
//英雄名字
char name[20];
//英雄血条
int Hp;
};
2.类声明放在.h文件中,成员函数定义放在.cpp文件中,注意:成员函数名前需要加类名::
Tower.h文件
#pragma once
class Tower
{
public:
//塔的攻击功能
int Attack();
private:
//塔的名字
char name[20];
//塔的血量
int Hp;
//塔的伤害值
int DamageValue;
};
Tower.cpp文件
#include"Tower.h"
int Tower::Attack()
{
return 0;
}
一般情况下,更期望采用第二种方式。好处现在可能不太明显,后面代码量上去后可能自己就有了体会,特别是还加了继承与多态。
类的访问限定符及封装
访问限定符
【访问限定符说明】
- public修饰的成员在类外可以直接被访问
- protected和private修饰的成员在类外不能直接被访问(此处protected和private是类似的)
- 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止
- 如果后面没有访问限定符,作用域就到 } 即类结束。
- class的默认访问权限为private,struct为public(因为struct要兼容C)
封装
C++中面向对象的特性有三:封装、继承、多态。学到这里代表少年面向对象的思想刚刚开始入门了。
封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互。假设你是王者荣耀的实现团队的leader,你希望你的团队写出在英雄放技能时可以修改英雄固定的属性值的代码吗?可能的不行的。
通过需要访问权限来隐藏对象内部实现细节,控制哪些方法可以在类外部直接被使用就是封装。
类的大小
前面在学习C语言的时候知道了结构体大小的计算,这里面主要涉及到内存对齐,同样类的大小计算也要涉及到内存对齐。比如:
那么为什么要有内存对齐规则呢?上次在C语言里没有细说,这次借助C++的类在这里展开一下。
为什么需要内存对齐
- 首先不是所有的硬件平台都能访问任意地址上的数据。
- 其次某些硬件平台只能只在某些地址访问某些特定类型的数据,否则抛出硬件异常,及遇到未对齐的边界直接就不进行读取数据了。
- 最后为了代码的可移植性,和提升CPU访问内存的效率,所以结构体一定要内存对齐。本质:空间换区时间的做法。
cpu的内存由于硬件的原因是一块一块的,块的大小可能是2字节、4字节、8字节取决于硬件,因此cpu在读取内存时是一块一块的读取的。不可以随机访问某一个地址,但是可以随机访问某个倍数倍的地址。比如:
最后对比一下对齐与不对齐的读取效率。如图:
为什么成员函数不占用类的内存?
话不多说直接上图:
通过2张图可以发现类的大小是真的与类内的成员函数无关。但是这是为什么呢?这主要与类的存储方式有关。如图:
成员函数不像成员属性那么特殊(每个对象的属性是独一无二的),成员函数就像是对象的方法你想用直接去公共代码区调用就好,不用每个对象都"带着"这样浪费空间。
为什么空类的大小是1个字节?
直接上图:
按道理应该是0呀?为什么是1呢?假设是0字节大小,即不在内存上存储。那么少年问你,对一个类取地址这个操作犯毛病吗?应该是合理的哟,但是它都不在内存上了它的地址是多少呢?所以为了出现这么的情况,编译器给了一个字节的空间来存储这个类,来证明这个类存在过。