面向对象编程,类,实例介绍
面向对象编程
面向对象编程,不是简单的定义变量和函数,而是一套更为复杂的代码组织方案,他倾向于以贴近现实或需求的某个事物为单位,完成其相关数据的存储和功能的实现。比如,在人事管理系统中,你可以把员工视为一个单位,并编写姓名,年龄,考核功能的代码。
虽然不需要全部,但支持面向对象编程的语言,应该具有以下的某些特点。
- 封装
- 封装是指对象可以隐藏其包含的数据和功能,仅公开特定的部分。外部仅能通过此部分来访问对象中的数据和使用对象中的功能。比如,员工拥有工资等级,但外部不能直接修改,只能通过员工的考核功能来重新评估他。
- 继承
- 继承是指通过某种方式,一个对象可以以另一个对象为基础,拓展新的数据和功能。比如,管理者从员工继承,拓展了新的管理规划功能。
- 多态
- 多态是指在继承中,对于同一功能,对象可以拥有不同的实现。比如,同样是考核功能,管理者考核的实现与员工不同。
为何使用面向对象编程?
试想仅采用变量和函数来完成一个超级复杂的项目,我们可能会拥有复杂的数组,以及参数众多的函数,这加大了维护的难度。面向对象编程缓解了这些情况,复杂的问题被分散在封装,继承,多态等特点中。
类
类是对象的设计蓝图,是对象的类型,他描述了对象包含哪些数据和功能。实例化后的类就是对象,对象也被称为类的实例。当然,“实例”一词并不局限于类,他也适用于接口,结构等其他概念。
类的成员
类的成员用于表述具体的数据和功能,从形式上可以划分为以下几类,当然,某些语言可能会支持更多。
- 字段/变量
- 类的字段用于存储数据,在一些语言中,他也被称为变量。
- 方法/过程
- 类的方法用于完成某种运算,你可以将其视为类所拥有的函数,在一些语言中,他也被称为过程。
- 属性
- 类的属性可用于限制或检验字段的访问,对外部来说,属性的用法与字段类似,但实际上属性是一种语法糖,其本质是方法。
- 构造器/构造函数
- 类的构造器也被称为构造函数,他给予了在创建对象时进行初始设置的机会,你可以使用其提供的参数来初始化字段或属性。构造器的名称不能随意指定,一般采用类名或某种特定名称,比如,
New
,constructor
等。
如果依据成员的归属,那么类的成员可以分为两大类。
- 实例成员
- 实例成员需要通过实例才能访问,虽然出现在类的定义中,但通过类是无法直接使用他们的。这种运作方式可以让每个实例拥有各自独立的数据,就像每位员工都应该拥有自己的姓名一样。
- 类成员/静态成员/共享成员
- 与实例成员不同,类成员可以通过类直接访问,类成员也被称为静态成员或共享成员。
如果依据读写规则,类的某些成员可以细分为三种。
- 可读写成员
- 可读写成员允许读取和写入,对于属性来说,需要拥有
get
和set
访问器。 - 只读成员
- 只读成员只允许读取,对于属性来说,只能拥有
get
访问器,对于字段则需要拥有特定关键字,比如readonly
。 - 只写成员
- 只写成员只允许写入,对于属性来说,只能拥有
set
访问器。
下面展示了 C# 类Employee
,他包含了实例字段name
和level
,类字段Count
,实例属性Name
,实例方法Evaluate
,以及一个构造器。
// 关于员工的类 Employee
class Employee
{
// 类字段 Count,记录创建过的 Employee 实例的个数
public static int Count;
// 字段 name,表示员工姓名
string name;
// 字段 level,表示员工工资等级
protected int level;
// 属性 Name,用于控制字段 name 的访问
public string Name
{
get { return name; }
set
{
// 员工姓名不接受没有意义的字符串
if (string.IsNullOrEmpty(name))
return;
name = value;
Console.WriteLine($"员工改名为:{name}");
}
}
// 方法 Evaluate,根据工作量评估员工的工资等级
public void Evaluate(int workload)
{
level = workload / 365;
Console.WriteLine($"员工 {Name} 的工资等级为:{level}");
}
// 构造器,用于初始化员工
public Employee(string n)
{
// 由于类字段 Count 归属于类而非某个实例,因此会一直累计
// 创建过的 Employee 实例的个数加 1
Count++;
// 初始化员工姓名
name = n;
}
}
类的成员访问级别
类的成员访问级别用于控制成员的可访问性,一般分为私有,保护,公共三种,其具体效果可能因语言的不同而不同。
- 私有
- 访问级别为私有的成员,只能在定义他的类或其实例中被访问。
- 保护
- 访问级别为保护的成员,在私有访问级别的基础上,还可以被派生类或其实例访问。关于派生类,会在稍后给出说明。
- 公共
- 访问级别为公共的成员,可以在任何位置被访问。
对于之前例子中定义的Employee
类,成员Count
,Name
,Evaluate
以及构造器的访问级别为公共,因此可在任意位置访问。
// 实例化类 Employee
Employee employee1 = new("小熊猫");
// 通过属性修改员工姓名
employee1.Name = "浣熊";
// 使用年工作量 12345 评估员工
employee1.Evaluate(12345);
// 显示创建过的 Employee 实例的个数
Console.WriteLine($"创建了 {Employee.Count} 个 Employee");
// 再次实例化类 Employee
Employee employee2 = new("大熊猫");
// 此时显示的个数为 2
Console.WriteLine($"创建了 {Employee.Count} 个 Employee");
员工改名为:浣熊
员工 浣熊 的工资等级为:33
创建了 1 个 Employee
创建了 2 个 Employee
类的继承
一个类可以继承自另一个类,这实现了面向对象编程的继承性,被继承的类被称为基类,父类或超类,而继承自基类的类,被称为派生类或子类。派生类拥有基类已定义的成员,并可在此基础上添加自己的新成员。
派生类Manager
继承自Employee
,虽然不能访问Employee
的私有成员name
,但他定义了一个新的公共方法Manage
,并访问了Employee
的非私有成员Name
和level
。
// 关于管理者的类 Manager
class Manager : Employee
{
// Manager 类加入了新的方法 Manage
public void Manage()
{
// 访问基类的非私有成员
Console.WriteLine($"{Name} 来管理自己了,哦,看下工资等级?{level}");
}
// 构造器,用于初始化管理者
public Manager(string n) : base(n) { }
}
// 实例化类 Manager
Manager manager = new("老熊猫");
// 调用 Manager 类定义的 Manage 方法
manager.Manage();
老熊猫 来管理自己了,哦,看下工资等级?0
什么是类的多级继承?
多级继承(Multilevel Inheritance)也被称为多层继承,是指某个派生类成为另一个类的基类的行为。比如,类B
是类A
的派生类,同时还是类C
的基类。
什么是类的多重继承?
多重继承(Multiple Inheritance)是指一个类从多个基类继承的行为,这种行为会产生多义性问题,即同一个基类被同一个派生类多次继承,导致派生类无法确定使用他们中的哪一个,在访问该基类成员的时候。需要指出,并非所有的语言都支持多重继承。
什么是类的虚继承?
类的虚继承主要用于解决多重继承带来的多义性问题,当一些类采用虚继承后,从这些类多重继承的派生类,将只拥有一份虚基类的成员。这里的虚基类是指被虚继承的基类。
在下面的 C++ 代码中,类C
多重继承自类B1
和B2
,因此类C
两次继承了类A
,在调用基类A
的Show
方法时,将无法确定是选择来自于B1
的A
,还是B2
的A
。
#include <iostream>
// 基类 A,拥有 Show 方法
class A
{
public:
void Show()
{
std::cout << "A::Show" << std::endl;
}
};
// 派生类 B1,B2 均继承自 A
class B1 : public A
{
};
class B2 : public A
{
};
// 派生类 C,将继承 A 两次
class C : public B1, public B2
{
};
// 创建实例,并调用 Show 方法
int main()
{
C c;
// ERROR 无法确定调用哪个 A 的 Show 方法
c.Show();
}
调整代码,将类B1
和B2
改为虚继承后,对方法Show
的调用不再有问题。
// 改为采用虚继承的方式
class B1 : virtual public A
{
};
class B2 : virtual public A
{
};
A::Show
类的多态
类的多态主要体现在本质是方法的成员上,当然,这包括方法本身,多态的应用体现了不同对象对功能差异化的需求。
内容分类
源码
classes.cs·codebeatme/programming·GitHub
classes.cpp·codebeatme/programming·GitHub