C#面向对象编程-类和对象(类的继承)

面对对象概述

对象是现实世界中的实体,它有三个基本要素分别为封装、继承和多态。而类则是将具有相似属性和方法的对象集合起来。
在学习C#的类之前,读者需要区分面向对象和面向过程这两种重要的思想。

  1. 面向过程
    面向过程是分析解决问题的步骤,然后用函数把这些步骤一步一步的实现,接着在使用时一一调用即可。
  2. 面向对象
    面向对象是把构成问题的事务分解成各个对象,而建立对象的目的也不是为了完成一个个步骤,而是为了描述某个事物在解决整个问题的过程中所发生的行为。意在写出通用代码,加强代码重用,屏敝差异性。
  3. 类与对象的关系
    类是一种抽象的数据类型,但是其抽象程度可能不同;而对象就是一个类的实例,例如车是一个类,而张三的一辆奔驰车就是一个对象,车的颜色就是它的属性,启动、停止这些动作则可以定义为车的方法。

类的继承

基类和派生类

在类的继承中,被继承的类叫基类或父类,继承的类叫派生类或子类。一个类可以派生自多个类或接口,这意味着它可以从多个基类或接口继承数据和方法。
C# 中创建派生类的语法如下:
<访问修饰符符> class <基类>
{ …}
class <派生类> : <基类>
{ …}
当一个类从另一个类派生出来时,派生类就自然具有基类的数据成员、属性和方法等。在基类中定义的这些成员,已经不需要在派生类定义中重写。在派生类的定义中,只需编写基类所不具有的代码即可。
编写程序,通过图形的基类,派生出一个矩形的类,并计算出它的面积。

using System;
namespace Project1
{
    class Shape    //图形
    {
        public void setWidth(int w)
        {
            width = w;
        }
        public void setHeight(int h)
        {
            height = h;
        }
        protected int width;
        protected int height;
    }
    class Rectangle : Shape    //长方形继承于Shape
    {
        public int getArea()
        {
            return (width * height);
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Rectangle Rect = new Rectangle();
            Rect.setWidth(6);
            Rect.setHeight(8);
            Console.WriteLine("总面积: {0}", Rect.getArea());
            Console.ReadKey();
        }
    }
}

【程序分析】本例演示类的继承。在代码中,首先创建一个基类Shape,在该类中声明了两个成员变量height与width,用于表示长和宽,同时还定义了两个获取长和宽的方法setWidth和setHeight;接着,根据基类Shape派生出一个矩形类Rectangle;然后在派生类Rectangle中定义一个计算面积的方法getArea;最后在Main方法中,调用setWidth和setHeight方法,并传入参数,通过计算输出矩形的面积。

总面积: 48

继承的特性

继承是在类之间建立的一种相交关系,使得新定义的派生类的实例,可以继承已有的基类的特征,并且还可以添加新的功能。下面是继承的一些特征:
(1) 派生类只能继承一个基类,所以C#并不支持多重继承,但一个基类可以有多个直接派生类。
编写程序,通过继承的方式,打印出一个公司里三位员工的自我介绍。

using System;
namespace Project2
{
    class Clerk     //创建一个职员的类
    {
        private string _name;   //定义职员姓名的字段
        public string Name     //定义职员姓名的属性
        {
            get
            { return _name; }
            set
            { _name = value; }
        }
        private string _department;  //定义职员部门的字段
        public string Department     //定义职员部门的属性
        {
            get
            { return _department; }
            set
            { _department = value; }
        }
        public void CSeyHello()
        {
            Console.WriteLine("大家好,我是{0}的{1}", Department, Name);
        }
    }
    class Sales : Clerk    //创建销售类Sales,继承于Clerk
    {
        private int _salesTarget;  //定义职员销售目标的字段
        public int SalesTarget     //定义职员销售目标的属性
        {
            get
            { return _salesTarget; }
            set
            { _salesTarget = value; }
        }
        public void SSayHello()
        {
            Console.WriteLine("大家好,我是{0}的{1},我的销售目标是{2}元", Department, Name, SalesTarget);
        }
    }
    //创建技术支持类TechnicalSupport,继承于Clerk
    class TechnicalSupport : Clerk
    {
        private double _satisfactionRate;  //定义职员服务满意度的字段
        public double SatisfactionRate     //定义职员服务满意度的属性
        {
            get
            { return _satisfactionRate; }
            set
            { _satisfactionRate = value; }
        }
        public void TSSayHello()
        {
            Console.WriteLine("大家好,我是{0}的{1},我的服务满意率为{2}分", Department, Name, SatisfactionRate);
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Clerk zs = new Clerk();
            zs.Name = "张三";
            zs.Department = "人力部";
            zs.CSeyHello();
            Sales ls = new Sales();
            ls.Name = "李四";
            ls.Department = "销售部";
            ls.SalesTarget = 5000;
            ls.SSayHello();
            TechnicalSupport zh = new TechnicalSupport();
            zh.Name = "周红";
            zh.Department = "技术支持部";
            zh.SatisfactionRate = 9.8;
            zh.TSSayHello();
            Console.ReadKey();
        }
    }
}

【程序分析】本例演示继承的单一特征。在代码中,首先创建一个职员的类Clerk,在该类中定义了字段_name与_department以及相关的属性,用于表示职员的姓名和部门;接着,再创建一个关于销售的类Sales,在该类中定义了字段_salesTarget和相关属性,用于表示销售目标;然后,再创建TechnicalSupport类,在该类中定义了_satisfactionRate和相关属性,用于表示服务的满意度。由于Sales类和TechnicalSupport类具有两个相同的属性,分别为姓名和部门。所以将Sales类继承于Clerk类,TechnicalSupport类也继承于Clerk类,这样Sales类和TechnicalSupport类就都具有了Clerk类的字段与属性。

大家好,我是人力部的张三
大家好,我是销售部的李四,我的销售目标是5000元
大家好,我是技术支持部的周红,我的服务满意率为9.8分

(2) 继承是可以传递的。
(3) 如果签名相同的方法在基类和派生类中都进行了声明,但该方法没有分别声明为virtual和override,派生类方法就会隐藏基类方法。
编写程序,在派生类中隐藏与基类同名的方法。

using System;
namespace Project3
{
    class myClass1
    {
        public void Write()
        {
            Console.WriteLine("这里是基类");
        }
    }
    class myClass2 : myClass1
    {
        public new void Write()   //隐藏方法
        {
            Console.WriteLine("这里是派生类");
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            myClass2 b = new myClass2();
            myClass1 a = b;
            a.Write();
            b.Write();
            Console.ReadKey();
        }
    }
}

【程序分析】本例演示派生类中隐藏基类成员的特征。在代码中,首先创建一个基类myClass1;接着再派生类myClass2;然后在这两个类中分别定义一个同名的方法Write。此时,编译器会对myClass2类中的Write方法发出警告:“myClass2.Write()隐藏继承的成员myClass1.Write()。如果是有意隐藏,请使用关键字new”。因为在大多数情况下,是要重写方法,而不是隐藏方法,并且隐藏方法会造成给定类的实例调用到错误的方法。所以,C#语法会在编译时收到这个潜在的错误警告。

这里是基类
这里是派生类

调用基类的构造函数

众所周知,基类的初始化工作由基类的构造函数完成,派生类的初始化工作则有派生类的构造函数完成,但是这样就产生了派生类构造函数的执行顺序问题。那么用户该如何获得基类的构造函数和自身的构造函数呢?本小节将通过实例一一验证。
(1) 当基类中没有定义构造函数时,派生类会默认的调用基类的默认构造函数。
(2) 当基类中编写一个有参构造函数后,再实例化派生类的对象,程序就会调用基类中无参的构造函数,如果该函数存在就调用它,否则编译器就会发出错误警告。因此,不论程序调用派生类中的哪个构造函数,都是在寻找基类中无参的构造函数,如果没有则报错,而非参数匹配。
(3) 基类中编写了构造函数,可以通过base关键字,指定创建派生类实例时应调用的基类构造函数。

base关键字还可以用于从派生类中访问基类的成员。
编写程序,在派生类中可以指定调用基类的某个构造函数。

using System;
namespace Project4
{
    public class myClass1        //基类
    {
        int Number;
        public myClass1()        //构造函数
        {
            Console.WriteLine("派生类调用基类的第一个构造函数");
        }
        public myClass1(int a)
        {
            Number = a;
            Console.WriteLine("派生类调用基类的第二个构造函数");
        }
        public int GetNumber()
        {
            return Number;
        }
    }
    public class myClass2 : myClass1            //派生类
    {
        //这个构造函数调用第一个基类的构造函数
        public myClass2() : base()            //派生类的构造函数
        {
        }
        //这个构造函数调用第二个基类的构造函数
        public myClass2(int a) : base(a)           //派生类的第二个构造函数
        {
        }
        static void Main()
        {
            myClass2 bs1 = new myClass2();
            myClass2 bs2 = new myClass2(1);
            Console.ReadKey();
        }
    }
}

【程序分析】本例演示base关键字的使用。在代码中,创建一个基类myClass1,并且定义两个构造函数,一个带参另一个不带参,再定义一个GetNumber方法,用于返回变量Number的值。接着,通过基类myClass1派生出类myClass2,并在该类中也分别定义一个带参和一个不带参的构造函数。然后实例化派生类的对象,通过base关键字指定调用基类的某个构造函数。

派生类调用基类的第一个构造函数
派生类调用基类的第二个构造函数
using System;
namespace Project5
{
    public class Person
    {
        protected string tel = "444-55-6666";
        protected string name = "张三";
        public virtual void GetInfo()
        {
            Console.WriteLine("姓名: {0}", name);
            Console.WriteLine("电话号码: {0}", tel);
        }
    }
    class Employee : Person
    {
        public string id = "ABC567EFG";
        public override void GetInfo()
        {
            base.GetInfo();          // 调用基类Getinfo方法
            Console.WriteLine("学号: {0}", id);
        }
    }
    class Program
    {
        static void Main()
        {
            Employee E = new Employee();
            E.GetInfo();
            Console.ReadKey();
        }
    }
}

【程序分析】本例演示base关键字的使用。在代码中,首先定义一个Person类,该类中定义了两个变量tel和name,分别用于表示人的电话号码与姓名,还定义了GetInfo方法,用于显示tel和name的信息;然后再定义一个类Employee继承于Person类,在该类中,定义了变量id,用于表示人的身份信息,接着通过base关键字调用基类中的GetInfo方法;最后在Main方法中进行实例化,输出所有身份信息。

姓名: 张三
电话号码: 444-55-6666
学号: ABC567EFG

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值