面向对象编程
学习过C语言的小伙伴知道:C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。
面向过程编程也叫结构化编程。虽然结构化编程的理念提高了程序的清晰度,可靠性,并且方便维护。但它再编写大型的程序时,仍然面临这巨大的挑战,OOP(面向对象编程)提供了一种新的方法。与强调算法的过程性编程不同的是,OOP强调的是数据。–引自《C++Primer Plus(第六版)》
类和对象
C结构体与C++类
在过程化编程中我们用结构体来描述一个复杂对象(这里用C语言举例)。在C语言中,结构体中只能定义变量。结构体关键字是struct。在C++中,结构体内不仅可以定义变量,还可以定义函数
struct Student
{void SetStudentInfo(const char* name, const char* gender, int age){strcpy(_name, name);strcpy(_gender, gender);_age = age;}void PrintStudentInfo(){cout << _name << " " << _gender << " " << _age << endl;}char _name[20];char _gender[3];int _age;
};
int main()
{Student s;s.SetStudentInfo("Peter", "男", 18);return 0;
}
上面结构体的定义, 在 C++ 中更喜欢用 class 来代替
class为定义类的关键字,ClassName为类的名字,{}中为类的主体,注意类定义结束时后面分号。
类中的元素称为类的成员:类中的数据称为类的属性或者成员变量; 类中的函数称为类的方法或者成员函数。
class Student
{
public:void SetStudentInfo(const char* name, const char* gender, int age){strcpy(_name, name);strcpy(_gender, gender);_age = age;}void PrintStudentInfo(){cout << _name << " " << _gender << " " << _age << endl;}
public:char _name[20];char _gender[3];int _age;
};
访问限定符
访问限定符说明:
- public修饰的成员在类外可以直接被访问
- protected和private修饰的成员在类外不能直接被访问(此处protected和private是类似的)
- 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止
- class的默认访问权限为private,struct为public(因为struct要兼容C)
**封装:**将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互。封装的本质是一种管理。 我们使用类数据和方法都封装到一下。 不想给别人看到的,我们使用 protected/private 把成员 封装 起来。 开放 一些共有的成员函数对成员合理的访问。所以封装本质是一种管理。
类的实例化
用类类型创建对象的过程,称为类的实例化
- 类只是 一个 模型 一样的东西,限定了类有哪些成员,定义出一个类 并没有分配实际的内存空间 来存储它
- 一个类可以实例化出多个对象, 实例化出的对象 占用实际的物理空间,存储类成员变量
- 做个比方。 类实例化出对象就像现实中使用建筑设计图建造出房子,类就像是设计图 ,只设计出需要什么东西,但是并没有实体的建筑存在,同样类也只是一个设计,实例化出的对象才能实际存储数据,占用物理空间
类对象模型
在C语言中,我们在学习结构体的时候知道,由于结构体中只定义变量,因此我们是可以计算出结构体的大小的。sizeof计算的是定义类型对象的大小。
那在C++中,由于类中不仅定义变量,还定义函数,那么类的大小是怎么计算的呢?
我们发现此类的大小还是12。
因此我们猜测:类对象的存储方式只保存成员变量,成员函数存放在公共的代码段。
那我们思考为什么采用这种方式呢?
在上述中说到,类就像是一份建筑图纸,而所建造的每一个房子中的name,capacity,top应当是不一样的。但是所调用的方法Init(),Top()应当是同一个方法。因此没有必要把函数在对象中存一份。我们也可以通过汇编看看不同的对象是否调用同一个函数。
我们能够发现st1和st2所调用得Init()函数是同一份。因此如果都把函数存在类中,就会造成浪费。因此我们可以把函数放在一个公共的区域,这个区域叫做代码段。
结论:一个类的大小,实际就是该类中”成员变量”之和,当然也要进行内存对齐,注意空类的大小,空类比较特殊,编译器给了空类一个字节来唯一标识这个类。注意:最小内存单元是1.操作系统规定都要有地址记录,就像sizeof(void) = 1。