前言
本文章旨在让读者简单初步认知类的使用,让读者初步了解类的基本思想:数据抽象和封装以及class关键字的基础用法。
类是什么
类的基本思想是数据抽象和封装,如何理解呢?如图:
首先,数据抽象依赖于接口和实现分离的编程设计。接口是提供给用户的,对用户可见的操作,比如部分成员函数(后面会讲),实现则是设计者自己设计的类内的成员变量,函数等。 而封装则是让接口和实现分离。让用户只能看到接口部分而无法访问实现部分。要实现类,首先需要一个抽象数据类型,在语言中就是自定义类型(struct 和 class)。
概念还是太晦涩难懂了,直接用例子和代码来分析吧。
我们先来设置一个结构体(自定义类型struct)用来代表人类这个抽象概念, 我们直接称呼这个人类的结构体为一个类,然后我们来完善它。在类内定义的变量称呼为成员变量,函数则称为成员函数。
//就是c语言中的结构体,c++在兼容c语言 // 语法的同时增加了许多操作和特性 struct person { //如可以声明和定义函数,这个函数代表人长一岁 void growup() { old++; } //也可以定义变量,在成员变量前加上 _ 是c++的一种编写风格, //没什么实际作用,只是更好区分是外面传的还是自己有的,可加可不加,建议加上 int _old;//年龄 int _gender;//性别 };
这就是类的基础实现了,growup函数就是设计提供给用户的接口(目前的代码中用户可以访问到growup函数)。
接下来我们来封装这个类。
struct person { void growup() { _old++; } int _old;//年龄 int _gender;//性别 }; //人类的类是一种抽象概念,我们可以用它来实例化一个人,张三 person zhangsan; //但一个人总有属于自己的年龄和性别,那如何在创建张三的同时给他赋予他自己的属性呢
c++引入了构造函数这个语法。首先先介绍c++类里的默认生成的函数。光看这个类的时候只能发现里面只有一个我们自己写的growup函数,但实际上编译器会帮我们隐式额外生成 8 个函数,我们在这里介绍几个初学者该认识的函数。
1 , 构造函数,在用类创建对象时自动调用,可以完成对对象的赋值,我们不自己写就会由编译器默认生成。不能显示调用,特点是函数不能有返回值,而且名字必须和类名相同。可以重载,重载多个时会根据传入参数的不同选择最合适的版本。可以有缺省值。这两个是c++函数的特点,看不懂不影响后续知识。
struct person { person(int old, int gender) { _old = old; _gender = gender; } ~person() { //我们这里不需要资源回收,可以不写 } void growup() { _old++; } int _old; int _gender; };
2,析构函数,只能有一个,不能有返回值,不能有形参,不能显示调用,以 ~ 开头后接名字,名字也要和类名相同。在对象销毁时自动调用,一般用来回收资源。
3,拷贝构造函数,拷贝赋值重载函数,取地址重载函数,const取地址重载函数,移动构造函数,移动赋值运算符重载。这 6 个涉及后面的知识,本文不做介绍。
struct person { person(int old, int gender) { _old = old; _gender = gender; } ~person() { //我们这里不需要资源回收,可以不写 } void growup() { _old++; } int _old; int _gender; }; int main() { //人类的类是一种抽象,我们可以用它来实例化一个人,张三 person zhangsan(1,1); //但一个人总有属于自己的年龄和性别,那如何在创建张三 //的同时给他赋予他自己的属性呢 //创建完成后我们调用提供的接口(用户可以访问) zhangsan.growup(); cout << zhangsan._old << endl;//输出2,表示调用成功,长大一岁,这里我们可以 //访问_old,就是实现部分,这不符合上文中类的定义,用户不能访问实现部分 return 0; }
封装则要让我们可以调用growup函数,而不能访问_old,_gender于是这里我们要引入一个新的概念:访问限定符(三种),
1, public : 不限制访问,使用类就可以访问,接口部分都放这
2,private:限制访问,只能再类内访问(类中的一个函数调用另一个),无法在类外访问,限制用户访问定义部分。
3,protected,在目前学习阶段可以认为和private功能相同,在继承部分才有具体区别,这里不讲。
使用方法,以上限定符 + : 后的部分都在它限制的范围,直到碰到下一个限定符或者类结束位置。
struct person { public: person(int old, int gender) { _old = old; _gender = gender; } ~person() { //我们这里不需要资源回收,可以不写 } void growup() { _old++; } private: int _old; int _gender; protected: };
到这里我们就完整的实现了一个类,接口和实现分离,完成了封装,抽象了人类这个概念,可喜可贺可喜可贺。
补充语法
1,有小伙伴久闻 class 大名却不见其踪影,这里我给大家介绍下struct 和 class的区别。在上面的访问限定符知识中,我们写类的时候可以什么限定符都不加,这时候struct默认是public的限定,class 默认 private。除此之外没有任何区别。所以我们可以在两个之间替换,完全没有任何问题。
class person { public: person(int old, int gender) { _old = old; _gender = gender; } ~person() { //我们这里不需要资源回收,可以不写 } void growup() { _old++; } private: int _old; int _gender; protected: };
2,类中只要自己写了构造函数,编译器就不会给你默认生成了,这构造函数包括,普通的构造函数,拷贝构造,移动构造,都是你自己写的。
3,类中是一个单独的作用域,类会先扫描所有声明,所以不用担心怕上面的函数找不打到下面的函数或者成员变量而额外写声明
4,类可以在类内声明,类外定义,有兴趣可以自己百度,这里就不多讲了,而且在类内定义的成员函数默认是inline内联的,可以看我上期博客。
给个赞吧,大伙。