前言
本文开始我们总结关于C++面向对象的相关概念,本文主要介绍C++中用来实现封装功能的类。
一、面向过程和面向对象(初步认识)
C语言是面向过程的语言,关注的是过程,要先分析出求解问题的过程,再通过函数调用一步一步的求解问题。
C++是基于面向对象的,关注的是对象,将一件事情分解成不同的对象,通过这些不同的对象之间的交互过程来完成一件事
用现实中洗衣服这件事举例:
面向过程:要关注洗衣服的过程,即洗衣服的每一个步骤。
面向对象:要关注洗衣服的对象,即洗衣服这件事的相关对象。
二、类
C语言的结构体(struct
)中只能定义变量,而在C++中,结构体内不仅可以定义变量,也可以定义函数,此时的结构体称为C++中的类。
1.类的定义
继承自C语言的struct
可以作为类的关键字,但是C++也有定义类的新关键字class
。
类的定义:
class className { // 类体:由成员函数和成员变量组成 }; // 一定要注意后面的分号
其中className
是类名,{}中是类体。
类体中的内容称为类的成员:类中的变量称为类的属性或者成员变量,类中的函数称为类的方法或者成员函数。
2.类的两种定义方式
1.声明和定义不分离
即声明和定义都放在类中,注意:成员函数如果在类中定义,编译器可能会将其当成内联函数处理。
//人 class person { public: //显示信息 void showInfo() { cout << _age << " " << _sex << " " << _name << " " << endl; } private: char* _name;//姓名 char* _sex;//性别 int _age;//年龄 };
2.声明和定义分离
即,将声明放在.h
文件中,将定义放置在.cpp
文件中,注意:成员函数名前需要加类名::
//person.h class person { public: //显示信息 void showInfo(); private: char* _name;//姓名 char* _sex;//性别 int _age;//年龄 };
//person.cpp #include"person.h" void person::showInfo()//注意:成员函数名前需要加类名::,作用域操作符 { cout << _age << " " << _sex << " " << _name << " " << endl; }
3.C++类中内些成员函数会被认为成内联函数?
- 隐式内联,在类中定义的成员函数;
class person { public: //显示信息 void showInfo() { cout << _age << " " << _sex << " " << _name << " " << endl; } private: char* _name;//姓名 char* _sex;//性别 int _age;//年龄 };
- 在类中显示声明为内联函数,在类外定义的成员函数;
class person { public: //显示信息 inline void showInfo();//显示声明为内联函数 private: char* _name;//姓名 char* _sex;//性别 int _age;//年龄 }; void person::showInfo() { cout << _age << " " << _sex << " " << _name << " " << endl; }
- 追加内联,在类中没有显示声明,但是在类外定义为内联函数。
class person { public: //显示信息 void showInfo(); private: char* _name;//姓名 char* _sex;//性别 int _age;//年龄 }; inline void person::showInfo()//类外定义为内联函数 { cout << _age << " " << _sex << " " << _name << " " << endl; }
类中不是内联函数的成员函数:
在类中没有显示声明,在类外定义也没有定义为内联函数。
class person { public: //显示信息 void showInfo(); private: char* _name;//姓名 char* _sex;//性别 int _age;//年龄 }; void person::showInfo() { cout << _age << " " << _sex << " " << _name << " " << endl; }
3.类的成员变量命名规则
先看一段代码:
class Date { public: void Init(int year) { // 问题来了,这里的year到底是成员变量,还是函数形参? year = year; } private: int year; };
计算机可以分辨出两个year分别对应的成员变量还是函数参数,但是这样的命名方式人不好理解,会增加阅读成本。
对此,我们应该采用将成员变量和函数参数定义为不同名的命名规则
class Date { public: void Init(int year) { _year = year; } private: int _year;//前缀_标识区分 };
或者
class Date { public: void Init(int year) { mYear = year; } private: int mYear;//前缀m标识区分 };
4.类的访问限定符及封装
C++实现封装的方式:用类将对象的属性与方法结合在一起,让对象更加完善,再通过访问权限选择性的将其接口提供给外部的用户使用。
1.访问限定符
访问限定符说明
public
在类外可以直接被访问private
在类外不可以直接被访问protected
在类外不可以直接被访问- 如果后面没有访问限定符,作用域就到 } 即类结束。
class
的默认访问权限为private
,struct
默认访问权限为public
(因为struct
要兼容C)
注意:访问限定符只在编译时有用,当数据映射到内存后,没有任何访问限定符上的区别
2.封装
封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来进行对象间的交互。
封装本质上是一种管理,让用户更方便的使用类。
举个例子:
对于计算机使用者而言,不用关心内部核心部件,比如主板上线路是如何布局的,CPU内部是如何设计的等。
用户只需要知道,怎么开机、怎么通过键盘和鼠标与计算机进行交互即可。
因此计算机厂商在出厂时,在外部套上壳子,将内部实现细节隐藏起来,仅仅对外提供开关机、鼠标以及键盘插孔等,让用户可以与计算机进行交互即可。
类似的,在C++语言中实现封装,可以通过类将数据以及操作数据的方法进行有机结合,通过访问权限来隐藏对象内部的实现细节,同时控制哪些方法可以在类外部直接被使用。
5.类的作用域
类定义了一个新的作用域,类的所有成员都在类的作用域中。如果要在类体外定义成员,则需要使用 ::
作用域操作符指明该成员属于哪个类域。
class Person { public: void PrintPersonInfo(); private: char _name[20]; char _gender[3]; int _age; }; // 这里需要指定PrintPersonInfo函数是属于Person这个类域 void Person::PrintPersonInfo() { cout << _name << " " << _gender << " " << _age << endl; }