一、类与对象的初步认识
C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题
C++是基于面向对象的,将一件事拆分成不同的对象,靠对象之间的交互完成
二、类的引用
C中,结构体只能定义变量,C++中,结构体不仅可以定义变量,也可以定义函数
struct Student
{
void Print()
{
cout << _name << " " << _gender << endl;
}
char _name[20];
char _gender[3];
int _age;
};
三、类的定义
class为定义类的关键字。
类中的元素为类的成员:类中的数据称为类的属性或者类的成员;类中的函数称为类的方法或者成员函数。
类的两种定义方式:
1.声明和定义全部放在类体中
class Person
{
public:
void Show()
{
cout << _name << "-" << _sex << "-" << _age << endl;
}
public:
char* _name;
char* _sex;
int _age;
};
2.声明放在.h文件中,类的定义放在.cpp文件中
//声明放在类的头文件person.h文件中
class Person
{
public:
void Show();
public:
char* _name;
char* _sex;
int _age;
};
//定义放在类的实现文件夹person.cpp文件中(一般采用)
#include"person.h"
void Person::Show()
{
cout << _name << "-" << _sex << "-" << _age << endl;
}
四、类的访问限定符及封装
1、访问限定符
访问限定符包括:public(公有)、protected(保护)、private(私有)
访问限定符说明:
(1)public修饰的成员在类外可以直接访问
(2)protected和private在类外不能直接被访问
(3)访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现为止
(4)class的默认访问权限为private,struct为public
2、封装
面向对象的三大特性:封装、继承、多态
封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互。
封装的本质是一种管理。
五、类的作用域
类定义了一个作用域。在类体外定义成员,需要使用::作用域解析符指明成员属于哪个类
class Person
{
public:
void Show();
public:
char* _name;
char* _sex;
int _age;
};
//这里需要指定Show是属于Person这个类域
void Person::Show()
{
cout << _name << "-" << _sex << "-" << _age << endl;
}
六、类对象模型
1、计算类对象的大小
类对象的存储方式:只保存成员变量,成员函数存放在公共代码区。因为每个对象的成员变量是不同的,但成员函数是相同的,当一个类创建多个对象,调用同一份函数时,相同代码保存多次,浪费空间。
class A1
{
public:
void f1(){}
private:
int _a;
};
class A2
{
public:
void f2(){}
};
class A3
{};
其中,sizeof(A1) = 4, sizeof(A2) = 1, sizeof(A3) = 1;
1意味占位,表示定义的对象存在过。
结论:一个类的大小,实际就是该类中“成员变量”之和,当然也要进行内存对齐。其中空类和只有成员函数的类,编译器给其一个字节来唯一标识这个类。
2、结构体内存对齐规则
(1)第一个成员在与结构体偏移量为0的地址
(2)其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
注:对齐数 = 编译器默认的一个对齐数与该成员大小的较小值
VS中默认的对齐数为8,gcc中的对齐数为4
(3)结构体总大小为:最大对齐数的整数倍
(4)如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数的整数倍
结构体内存对齐的原因:“以空间换时间”,浪费空间,提高效率
七、this指针
class Date
{
public:
void Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
void SetDate(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1, d2;
d1.SetDate(2019, 1, 16);
d2.SetDate(2018, 12, 1);
d1.Print();
d2.Print();
return 0;
}
上述代码中,Date类中有Print和SetDate两个成员函数,函数体中并没有关于不同对象的区分,当d1调用SetDate函数时,就会有this指针来区分是设置d1对象,还是设置d2对象。
C++编译器给每个“成员函数”增加了一个隐形的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象)。该指针就是this指针。
this指针的特性:
(1)this指针的类型:类类型
(2)只能在成员函数的内部使用
(3)this指针本质上是一个成员函数的实参,是对象调用成员函数时,将对象的地址作为实参床底给this形参。
所以对象中不存储this指针。(this指针存在于栈帧中,但编译器优化后,存在于寄存器中)
(4)this指针是成员函数第一个隐含的指针形参,一般情况由编译器通过exc寄存器自动传递。
void Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
//编译器处理成员函数隐含的this指针
void Print(Date* this)
{
cout << _year << "-" << _month << "-" << _day << endl;
}