一、类的定义
class className
{
// 类体:由成员函数和成员变量组成
}; // 一定要注意后面的分号
class为定义类的关键字,ClassName为类的名字,{}中为类的主体,注意类定义结束时后面分号不能省略。
类体中内容称为类的成员:类中的变量称为类的属性或成员变量; 类中的函数称为类的方法或者成员函数。
类的两种定义方式:
1. 声明和定义全部放在类体中,需注意:成员函数如果在类中定义,编译器可能会将其当成内联函数处理。
class people
{
public:
void Init()
{
name = nullptr;
age = 18;
weith = 50.0;
}
private:
char* name;
int age;
double weith;
};
2. 类声明放在.h文件中,成员函数定义放在.cpp文件中(声明和变量分离),注意:成员函数名前需要加类名::
//text.h中
class People
{
public:
void Init();
public:
char* name;
int age;
double weigtht;
};
//text.cpp中
void People::Init()
{
name = nullptr;
age = 18;
weigtht = 50.0;
}
二、类的访问限定符及封装
2.1访问限定符
C++实现封装的方式:用类将对象的属性与方法结合在一块,让对象更加完善,通过访问权限选择性的将其接口提供给外部的用户使用。
访问限定符说明:
1. public修饰的成员在类外可以直接被访问。
2. protected和private修饰的成员在类外不能直接被访问(此处protected和private是类似的)。
3. 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止。
4. 如果后面没有访问限定符,作用域就到 } 即类结束。
5. class的默认访问权限为private,struct为public(因为struct要兼容C)。
注意:访问限定符只在编译时有用,当数据映射到内存后,没有任何访问限定符上的区别。
2.2封装
封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互。
封装本质上是一种管理,让用户更方便使用类。比如:对于电脑这样一个复杂的设备,提供给用户的就只有开关机键、通过键盘输入,显示器,USB插孔等,让用户和计算机进行交互,完成日常事务。但实际上电脑真正工作的却是CPU、显卡、内存等一些硬件元件。
三、类的作用域
类定义了一个新的作用域,类的所有成员都在类的作用域中。在类体外定义成员时,需要使用 :: 作用域操作符指明成员属于哪个类域。
四、类的实例化
用类类型创建对象的过程,称为类的实例化。
1. 类是对对象进行描述的,是一个模型一样的东西,限定了类有哪些成员,定义出一个类并没有分配实际的内存空间来存储它;比如:入学时填写的学生信息表,表格就可以看成是一个类,来描述具体学生信息。类就像谜语一样,对谜底来进行描述,谜底就是谜语的一个实例。
2. 一个类可以实例化出多个对象,实例化出的对象占用实际的物理空间,存储类成员变量。
//类
class Person
{
public:
void Init()
{
name = nullptr;
age = 18;
weigtht = 50.0;
}
public:
char* name;
int age;
double weigtht;
};
int main()
{
Person p1;//实例化出的对象
}
如上述代码所示,p1是实例化出的对象,在内存中占有实际的空间,而Person是一个类,用来,用来描述对象的信息,所以可以把类和对象看作是建筑图纸和建造出来的房子一般的关系。
五、类对象模型
5.1计算类对象的存储大小
在学习C语言阶段,我们学习过计算结构体的大小,但是对于类,它与结构体又有不同,类不仅包含类成员变量还包括类成员函数。
所以类在内存中的存储是只存储类成员函数,还是类成员变量、还是都存储呢?那么存储的规则是什么呢?我们以代码来学习:
class Date
{
//初始化
void DateInit(int year = 1, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
//打印
void Print()
{
cout << _year << "年" << _month << "月" << _day << "日" << endl;
}
private:
int _year;
int _month;
int _day;
};
对于这么一个日期类,我们可以大致分为三个思路:
1、将类成员变量和类成员函数全部存储。
如此一来,每个对象中成员变量是不同的,但是调用同一份函数,如果按照此种方式存储,当一个类创建多个对象时,每个对象中都会保存一份代码,相同代码保存多次,浪费空间。
2、代码只保存一份,在对象中保存存放代码的地址。
3、只保存成员变量,成员函数存放在公共的代码段
对于上述三种方式的猜想,我们编写三个相应的代码,来确认哪一个是正确的。
//既有类成员变量又有类成员函数
class text1
{
void show()
{
;
}
private:
int _n;
};
//仅有类成员函数
class text2
{
void show()
{
;
}
};
//空类
class text3
{
};
int main()
{
text1 t1;
text2 t2;
text3 t3;
cout << "类text1为:" << sizeof(t1) << endl;
cout << "类text2为:" << sizeof(t2) << endl;
cout << "类text3为:" << sizeof(t3) << endl;
return 0;
}
代码结果为:
由此可见,一个类的大小,实际就是该类中”成员变量”之和,当然要注意内存对齐注意空类的大小,空类比较特殊,编译器给了空类一个字节来唯一标识这个类的对象。
5.2结构体内存对齐规则
1. 第一个成员在与结构体偏移量为0的地址处。
2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
注意:对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
VS中默认的对齐数为8。
3. 结构体总大小为:最大对齐数(所有变量类型最大者与默认对齐参数取最小)的整数倍。
4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整
体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。