一、类的概念
1. 基本概念
??C++ 中的 类 (Class) 可以看做 C 中 结构体 (Struct) 的升级版:可以包含函数的结构体。 ??结构体和类都是构造类型,是由用户自己定义的复杂数据类型,是一系列基本数据类型通过用户自己规定的方式组合起来得到的集合体。在 C 中可以使用结构体名定义变量,在 C++ 中可以使用类名定义变量,不同的是,通过结构体定义出来的变量还是叫变量,而通过类定义出来的变量有了新的名称:对象 (Object) 。 除了可以包含函数以外,类还拥有许多结构体所不具有的特性,如:继承、多态等等。
- 类的成员的别称
??在面向对象的编程语言中,常把类的 成员变量 称为 类的属性 (Property),把类的 成员函数 称为 类的方法 (Method) - C++ 语法不提供现成的类
??类是用户自定义的类型,程序中使用时必须提前说明,或者使用已存在的类(别人写好的、标准库中的类等),C++ 语法本身并不提供现成的类的名称、结构或内容。
2. 对类和对象的理解
??类是一个模板(Template),一个用来描绘编程者自创的数据类型的模板。由于只是描绘结构而未实际创建变量,其编译后并不会占用内存空间,因此也不能在定义时对成员变量进行初始化,因为没有地方存储数据。只有在创建对象后,系统才会给成员变量分配内存空间,这时才能对成员变量进行赋值。 ??为了更好地理解,我们可以将类比喻成图纸,则对象是根据这个图纸制造的零件。图纸说明了零件的属性(成员变量与成员函数),根据一张图纸可以制造出任意数量性质相同的零件,而根据不同的图纸生产出的零件是不一样的。 ??类只是一张图纸,起到说明的作用,不占用内存空间;对象是具体的零件,是实际存在的实体,需要空间来存放。
3. 面向过程编程(POP)与 面向对象编程(OOP)
??类是一个被广泛使用的概念,C++、Java、C#、PHP 等很多编程语言中都支持类。可以将类看做是结构体的升级版,C语言的晚辈们看到了C语言的不足,尝试加以改善,继承了结构体的思想,并进行了升级,让程序员在开发或扩展大中型项目时更加容易。
1)面向过程编程(POP,Procedure Oriented Programming)的项目组织方式:
??面向过程编程中,函数和变量各自离散存在,它们归束到不同的源文件之中,所有源文件结合起来组成一个项目整体。
2)面向对象编程(OOP,Object Oriented Programming)的项目组织方式:
??相比面向过程编程,面向对象编程新增了「类」的层级:相互联系的函数与变量根据一定规则打包到不同的类之中,来共同实现一定的功能。一个源文件中包含许多类,所有源文件结合起来组成一个项目整体。
??面向对象编程在代码执行效率上并没有优势,它的主要目的是方便程序员组织和管理代码,快速梳理编程思路,带来编程思想上的革新。 ??( 也就是:代码效率 换 开发效率 )
二、类的基本操作(+)
1. 类的定义
??类的定义通过关键字 < class > 来实现,其定义方法如下所示:
??语法格式:
class class_Name {
access specifier:
Member Variables;
Member Functions();
};
??成员函数可以直接定义在类体内部,这样就会被自动声明为「内联」的;也可以定义在类体外部,这样就需要使用 <域解析运算符> 来指明定义的函数所属于的类。
??内部定义方法:
================================ 在内部定义成员函数 ================================
class Student{
public:
char * m_name;
int m_age;
float m_score;
void query (void) {
printf("-> 学生姓名: %s, 年龄: %d, 成绩: %f \n", m_name, m_age, m_score);
}
};
??外部定义方法:
================================ 在外部定义成员函数 ================================
class Student {
public:
char * m_name;
int m_age;
float m_score;
void query (void);
}
void Student::query (void) {
printf("-> 学生姓名: %s ; 年龄: %d ; 成绩: %.2f \n", m_name, m_age, m_score);
}
inline void Student::query (void) {
printf("-> 学生姓名: %s ; 年龄: %d ; 成绩: %.2f \n", m_name, m_age, m_score);
}
-
示例中 Student 是类的名称,类名通常大写首字母,而成员变量大都以 “m_” 开头,这并不是语法规定的内容,而是约定成俗的写法。类名大写是为了和其他标识符区分开,以 “m_” 开头既可以一眼看出这是成员变量,又可以和成员函数中的形参名字区分开,这都是为了提高代码可读性,让工程更加条理清晰而达成的一种默契。 -
{ } 内部是类所包含的成员变量和成员函数,统称为 类的成员 (Member)。由 { } 包围起来的部分也称为 类体,和函数体的概念类似。 -
< public > 是 C++ 中的关键字,仅用在类的定义中,用来修饰类的成员的访问权限为“公开”。(public、protected、private) -
在类定义的最后有一个分号 " ; " ,它是类定义的一部分,表示类的定义的结束,不能省略。
2. 创建对象
??有了 图纸(类) 之后就可以根据图纸制作 零件(对象) 了。根据类创建对象的过程叫「类的实例化」,每个对象都是类的一个 具体实例(Instance),拥有类的 成员变量(属性) 和 成员函数(方法)。
================================ 类的创建方法 ================================
1. 一般创建方法
class Student stu;
2. 省略关键字<class>的创建方法
Student stu;
3. 创建对象数组
Student stu[50];
??可以看出 通过类创建对象 与 通过结构体定义变量 是十分相似的,二者的本质都是 “通过程序员自定义的构造模板创造程序员自定义的复杂数据类型” 的行为。
3. 类的访问
1)通过对象实体访问
??创建对象之后,可以使用 " . " 运算符来访问其成员变量和成员函数,这与访问结构体的成员变量的方式相同。
================ 通过实体访问对象成员 ================
class Student stu;
stu.m_name = "张三";
stu.m_age = 16;
stu.m_score = 84.5f;
stu.query();
2)通过对象指针访问
??C 中经典的指针在 C++ 中仍广泛使用,C 中有指向结构体的指针,而 C++ 中有指向对象的指针。
================ 创建对象指针 ================
1.使用一般方法
Student stu;
Student * pStu = &stu;
2.使用 C++ 中的 new 关键字
Student * pStu = new Student;
??C++ 中通过对象指针访问对象成员的方式与 C 中通过结构体指针访问结构体成员的方式相同,也是通过 " -> " 运算符。
================ 通过指针访问成员 ================
pStu -> m_name = "张三"
pStu -> m_age = 16;
pStu -> m_score = 84.5f;
pStu -> say();
三、类的访问权限(+)
1. 访问权限修饰关键字
- 类的访问权限通过三个关键字:public (公有)、private (私有)、protected (受保护) 来修饰。
- 被声明为 public 的成员可以被任意访问
- 被声明为 private 的成员仅可以在类的内部被访问
- 被声明为 protected 的成员不可以被外部访问,但可以在它的派生类的内部被访问
-
如果成员 既不声明为 private 也不声明为 public,则默认为声明为 private 。(类的成员默认声明为 private) -
关键字的修饰范围为从关键字开始一直到下一个修饰访问权限的关键字出现为止(没有则一直到类的定义结束) -
在类的内部,无论成员被声明为 public、private 或是 protected,都是可以互相访问的,没有限制。 在类的外部,只能通过对象访问成员,且只能访问 public 属性的成员,不能访问 private、protected 属性的成员。 -
Java、C# 程序员注意,C++ 中的 public、private、protected 只能修饰类的成员,不能修饰类,C++中的类没有共有私有之分。
2. 类的封装思想
1)封装的概念
??所谓 封装 即:把内部复杂的实现过程与细节等内容隐藏起来,仅对用户提供简洁有效的使用方法。在OOP中,类的封装是指:尽量隐藏对用户无意义的类的内部实现,只向用户提供有用的成员函数(方法)。 ??封装是一个广泛存在的概念,是人类的工程项目在发展中日渐复杂伴随着分工协作的日益加强所带来的必然结果。封装的目的旨在实现更好的模块化,其方式主要为 降低耦合 和 简化繁杂:
-
降低耦合:封装通过隐藏内部细节,使类的创建者可以规定外部访问类的方式,阻止外部可能的不合法访问以及避免混乱的代码逻辑 ??如果对类的属性不做限制而使外部可以肆意访问,那么确实是增强了灵活性,但是灵活性也意味着"不可控性"。对外部开放更多的操作意味着要更加相信它的使用者,但正如那句经典名言:“永远不要相信用户的输入” 所言,我们永远不知道产品的使用者是否奇葩、有多奇葩,在一切未知的情况下如果要最大可能地保证功能的正常运转,就必须默认用户是个绝顶傻瓜。以最低限度的眼光看待用户、以最全面的方式审查过程与细节、以最严格的态度控制访问方式,才能最大程度地杜绝一切非法的、错误的操作及其带来的不利影响,预防未知的、可能的错误和问题。这是现代程序设计的重要规范,是保证模块化设计质量的必要规范,深刻地影响着程序的健壮性。 ??同时,由创建者提供规范的访问方式能杜绝使用者的混乱代码逻辑。如果开放内部属性的任意访问,那么属性可以在工程的任何角落以任何可能的(正常或是奇葩的) 方式被修改,势必会影响代码的可读性与可维护性。通过创建者建立一套规范的访问机制能够避免这些烦人的问题,从而提高程序的规范性和可维护性。 -
简化繁杂:封装通过隐藏内部实现方法,仅提供简洁的函数接口,提高类的易用性。 ??如果你购买一个冰箱,使用时却需要知道如何驱动压缩机,那你肯定会对厂家愤怒到无以吐槽,所以最后我们用上的冰箱有简洁的控制按钮,或者是一个先进的图形触控操作界面,亦或是更先进的智能家居APP。 ??这就揭示了封装的另一个目的:屏蔽繁杂的实现细节,提供简洁的使用方法。 ??用户不需要知道怎么调制信号,怎么驱动压缩机,怎么使用算法控制温度恒定在预定值——这些是制造者们要考虑的问题,无论是实现还是细节,这些统统都是制造者的工作,是用户不需要知道的繁杂又多余的内容;用户需要知道的仅仅是怎么操控触控板来控制冰箱。冰箱制造厂商完成了冰箱的制造,使用冰箱外壳屏蔽了冰箱的内部细节,然后提供了触控面板给用户以简单快捷地使用冰箱,我们使用类即是如此:创建者编写完类,通过private封装来屏蔽内部细节,再通过public的方法向外部提供简单快捷的使用方法。 ??至此我们就生动地理解了封装如何简化繁杂,也明白了现代化模块化设计的思维:我负责我的(制造),你负责你的(使用),我们分工明确。
2)封装的要点:
-
类的封装设计规范 ??根据 C++ 软件设计规范,类的成员变量以及只在类内部使用的成员函数(只被成员函数调用的成员函数)都建议声明为 private,而只将允许通过对象调用的成员函数声明为 public。 ??即:??①该向外暴露的接口都应声明为 public, ??????②不希望外部知道、只在类的内部使用、对外部没有影响的成员都建议声明为 private 。 -
如果将成员变量都声明为 private,又如何访问他们呢? ??我们可以通过 “设置公开的内部函数” 的方法来实现 “IO”:创建一个 public 方法 set_xxx() 来赋值,创建一个 public 方法 get_xxx() 来读取。赋值函数以 " set_ " 开头,读取函数以 " get_ " 开头是一种默契,旨在使得代码更加易读。
四、静态成员(Static Member)
1. static
??< this > 是 C++ 中的一个关键字,也是一个 const 指针,它指向当前对象,通过它可以访问当前对象的所有成员。
|