URLhttps://learnscript.net/zh/programming/object-oriented/
    复制链接转到说明  示例

    面向对象编程,类,实例介绍

    我被代码海扁署名-非商业-禁演绎
    阅读 10:02·字数 3012·发布 

    面向对象编程

    面向对象编程,不是简单的定义变量和函数,而是一套更为复杂的代码组织方案,他倾向于以贴近现实或需求的某个事物为单位,完成其相关数据的存储和功能的实现。比如,在人事管理系统中,你可以把员工视为一个单位,并编写姓名,年龄,考核功能的代码。

    虽然不需要全部,但支持面向对象编程的语言,应该具有以下的某些特点。

    封装

    封装是指对象可以隐藏其包含的数据和功能,仅公开特定的部分。外部仅能通过此部分来访问对象中的数据和使用对象中的功能。比如,员工拥有工资等级,但外部不能直接修改,只能通过员工的考核功能来重新评估他。

    继承

    继承是指通过某种方式,一个对象可以以另一个对象为基础,拓展新的数据和功能。比如,管理者从员工继承,拓展了新的管理规划功能。

    多态

    多态是指在继承中,对于同一功能,对象可以拥有不同的实现。比如,同样是考核功能,管理者考核的实现与员工不同。

    为何使用面向对象编程?

    试想仅采用变量和函数来完成一个超级复杂的项目,我们可能会拥有复杂的数组,以及参数众多的函数,这加大了维护的难度。面向对象编程缓解了这些情况,复杂的问题被分散在封装,继承,多态等特点中。

    类是对象的设计蓝图,是对象的类型,他描述了对象包含哪些数据和功能。实例化后的类就是对象,对象也被称为类的实例。当然,“实例”一词并不局限于类,他也适用于接口,结构等其他概念。

    类的成员

    类的成员用于表述具体的数据和功能,从形式上可以划分为以下几类,当然,某些语言可能会支持更多。

    字段/变量

    类的字段用于存储数据,在一些语言中,他也被称为变量。

    方法/过程

    类的方法用于完成某种运算,你可以将其视为类所拥有的函数,在一些语言中,他也被称为过程。

    属性

    类的属性可用于限制或检验字段的访问,对外部来说,属性的用法与字段类似,但实际上属性是一种语法糖,其本质是方法。

    构造器/构造函数

    类的构造器也被称为构造函数,他给予了在创建对象时进行初始设置的机会,你可以使用其提供的参数来初始化字段或属性。构造器的名称不能随意指定,一般采用类名或某种特定名称,比如,Newconstructor等。

    如果依据成员的归属,那么类的成员可以分为两大类。

    实例成员

    实例成员需要通过实例才能访问,虽然出现在类的定义中,但通过类是无法直接使用他们的。这种运作方式可以让每个实例拥有各自独立的数据,就像每位员工都应该拥有自己的姓名一样。

    类成员/静态成员/共享成员

    与实例成员不同,类成员可以通过类直接访问,类成员也被称为静态成员或共享成员。

    如果依据读写规则,类的某些成员可以细分为三种。

    可读写成员

    可读写成员允许读取和写入,对于属性来说,需要拥有getset访问器。

    只读成员

    只读成员只允许读取,对于属性来说,只能拥有get访问器,对于字段则需要拥有特定关键字,比如readonly

    只写成员

    只写成员只允许写入,对于属性来说,只能拥有set访问器。

    下面展示了 C# 类Employee,他包含了实例字段namelevel,类字段Count,实例属性Name,实例方法Evaluate,以及一个构造器。

    classes.cs
    // 关于员工的类 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类,成员CountName,Evaluate以及构造器的访问级别为公共,因此可在任意位置访问。

    *.cs
    // 实例化类 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的非私有成员Namelevel

    classes.cs
    // 关于管理者的类 Manager
    class Manager : Employee
    {
    	// Manager 类加入了新的方法 Manage
    	public void Manage()
    	{
    		// 访问基类的非私有成员
    		Console.WriteLine($"{Name} 来管理自己了,哦,看下工资等级?{level}");
    	}
    
    // 构造器,用于初始化管理者 public Manager(string n) : base(n) { } }
    *.cs
    // 实例化类 Manager
    Manager manager = new("老熊猫");
    // 调用 Manager 类定义的 Manage 方法
    manager.Manage();
    老熊猫 来管理自己了,哦,看下工资等级?0

    什么是类的多级继承?

    多级继承(Multilevel Inheritance)也被称为多层继承,是指某个派生类成为另一个类的基类的行为。比如,类B是类A的派生类,同时还是类C的基类。

    什么是类的多重继承?

    多重继承(Multiple Inheritance)是指一个类从多个基类继承的行为,这种行为会产生多义性问题,即同一个基类被同一个派生类多次继承,导致派生类无法确定使用他们中的哪一个,在访问该基类成员的时候。需要指出,并非所有的语言都支持多重继承。

    什么是类的虚继承?

    类的虚继承主要用于解决多重继承带来的多义性问题,当一些类采用虚继承后,从这些类多重继承的派生类,将只拥有一份虚基类的成员。这里的虚基类是指被虚继承的基类。

    在下面的 C++ 代码中,类C多重继承自类B1B2,因此类C两次继承了类A,在调用基类AShow方法时,将无法确定是选择来自于B1A,还是B2A

    classes.cpp
    #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(); }

    调整代码,将类B1B2改为虚继承后,对方法Show的调用不再有问题。

    classes.cpp
    // 改为采用虚继承的方式
    class B1 : virtual public A
    {
    };
    class B2 : virtual public A
    {
    };
    A::Show

    类的多态

    类的多态主要体现在本质是方法的成员上,当然,这包括方法本身,多态的应用体现了不同对象对功能差异化的需求。

    内容分类

    源码

    classes.cs·codebeatme/programming·GitHub
    classes.cpp·codebeatme/programming·GitHub