对象的介绍
C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题;
C++是基于面向对象的,关注的是对象,将一件事拆分成不同的对象,靠对象之间的交互完成,实际上对象这个翻译是不准确的,侯捷在翻译《Effective C++》中就说到,object的真正意义是“物体、物件”而不是“对象、目标”。不过大多数人在学习的时候都被告知了对象的意思是有别于原意,因此程序员对对象这一词的认知应该是要比其他人多一个释义的。
个人认为对象有点类似于数据库中抽象出的实体,对象就是逻辑上存在这一东西,不是一定要现实中就看得见摸得着,然后它们各自具备能够相互区分的属性。
举个例子,我要从绵阳到成都。面向过程:买票->进站->候车->检票->乘车->到站->下车->出站;而面向对象则是关注什么与什么交互,我要从绵阳到成都,那对象就是我(或者说人)、车站、车三个对象之间的交互。
类的介绍
在C语言中,结构体只能用来定义变量。但是C++中的结构体不仅可以定义变量,也能够定义函数。在C++中struct可以被用来实现一个类,但是C++中更常用的还是class。
//这里只是用来说明struct可以实现一个类,之后会用class typedef int DataType; struct Stack { void Init(size_t capacity) { _array = (DataType*)malloc(sizeof(DataType) * capacity); if (nullptr == _array) { perror("malloc申请空间失败"); exit(-1); } _capacity = capacity; _size = 0; } void Push(const DataType& data) { _array[_size] = data; ++_size; } DataType Top() { return _array[_size - 1]; } void Destroy() { if (_array) { free(_array); _array = nullptr; _capacity = 0; _size = 0; } } DataType* _array; size_t _capacity; size_t _size; }; int main() { Stack s; s.Init(10); s.Push(1); s.Push(2); s.Push(3); cout << s.Top() << endl; s.Destroy(); return 0; }
class是定义的关键字,类体中内容称为类的成员:类中的变量称为类的属性或成员变量;类中的函数称为类的方法或者成员函数。
类的两种定义方式
声明和定义全部放在类体中,需要注意的是,如果成员函数在类中定义,编译器可能会将其当成内联函数处理。
class Student { public: void showInfo() { cout << _name << "-" << _sex << "-" << _sno << endl; } public: char* _name; char* _sex; int _sno; };
类的声明放在.h文件中,成员函数定义放在.cpp文件中。需要注意的是,成员函数名前需要加 类名::
class Teacher { public: void showInfo(); public: char* _name; char* _sex; int _tno; };
void Teacher::showInfo() { cout << _name << "-" << _sex << "-" << _tno << endl; }
类的访问限定符及封装
访问限定符
C++实现封装的方式:用类将对象的属性与方法结合在一块,让对象更加完善,通过访问权限选择性将其接口提供给外部的用户使用。
访问限定符:public(公有)、protected(保护)、private(私有)。
public修饰的成员在类外可以直接被访问;
protected和private修饰的成员在类外不能直接被访问;
访问权限作用域从该访问限定符出现的位置开始到一下个访问限定符出现为止;
如果后面没有访问限定符,作用域就到类结束为止;
class的默认权限是private,struct为public(因为要兼容C语言);
访问限定符只在编译时有用,当数据映射到内存后,没有任何访问限定符上的区别
封装
封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互。
封装本质上是一种管理,让用户更方便实用类。在C++语言中实现封装,可以通过类将数据以及操作数的方法进行有机结合,通过访问权限来隐藏对象内部实现细节,控制哪些方法可以在类外部直接被使用。
类的作用域
类定义了一个新的作用域,类的所有成员都在作用域中。在类体外定义成员时,需要使用 :: 作用域操作符指明成员属于哪个类域。
//这里说明showInfo是属于Teacher这个类域的 void Teacher::showInfo() { cout << _name << "-" << _sex << "-" << _tno << endl; }
类的实例化
用类创建对象的过程称为实例化。
类是对对象的描述,是一个模型一样的东西,限定了类有哪些成员,定义出一个类并没有分配实际的内存空间来存储它。只有在实例化之后,才为实例化后的对象开辟了空间。
一个类可以实例化出多个对象。
class Student { public: void showInfo() { cout << _name << "-" << _sex << "-" << _sno << endl; } public: char* _name; char* _sex; int _sno; }; void test() { Student zs; zs._name = (char*)"张三"; zs._sex = (char*)"男"; zs._sno = 01; zs.showInfo(); } int main() { test(); return 0; }
类的对象模型
类对象在存储时,存储的是成员对象,成员函数并不存放在对象中。每个对象的成员变量是不一样的,但是成员函数是相同的。如果每个对象里面都放一个成员函数,这样并不是一个高效的方法。最好的方法是把成员函数放到一个共享的公共区域里面,然后需要使用时去该区域进行调用。这个区域被叫做代码段。
所以一个类的大小,实际上就是成员变量的和,因为成员函数被存放在代码段了。类里面的成员变量也需要进行内存对齐,对齐方式与结构体的对齐方式一致。需要注意的是一个空类的大小是一字节,而并非零字节。编译器需要一个标识来识别这个类的对象。