Keep on going never give up.

Let's Go

C# 学习笔记(40)面向对象三大特性之继承

C#Lonely2019-05-16 18:56:0720次0条

在c#中,一个类可以继承另外一个已有的类(密封类除外),被继承的类称为基类(或父类),继承的类称为派生类(或子类),子类将获得基类除构造函数和析构函数以外的所有成员。此外,静态类是密封的,也不能被继承。

例如,学生、老师、程序员等都是属于人类,但他们是不同职业的人类,除了具有人类的共同性外,他们还具有各自的特点,如不同的身份、不同的工作方式等。我们可以把人类定义为学生、老师、程序员的父类,这样子类不但继承了基类除构造函数和析构函数以外的所有成员,还可以添加自己特有的成员。

通过继承,程序可实现对父类代码的复用。因为子类可继承父类的所有成员,父类中定义的代码便不需要在子类中进行重复定义了。

代码示例:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp
{
    class Person
    {
        private string _name;
        private char _sex;
        private int _age;
        
        public string Name
        {
            get
            {
                return _name;
            }
            set
            {
                _name = value;
            }
        }
        
        public char Sex
        {
            get
            {
                return _sex;
            }
            set
            {
                _sex = value;
            }
        }
        
        public int Age
        {
            get
            {
                return _age;
            }
            set
            {
                _age = value;
            }
        }
        
        public Person(string name,char sex,int age)
        {
            this.Name = name;
            this.Sex = sex;
            this.Age = age;
            Console.WriteLine("我是Person类的构造函数,我被调用了");
        }
        
        public void SayHello()
        {
            Console.WriteLine("大家好!我是人类");
        }
        
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp
{
    class Student: Person //Student类继承Person类
    {
        private int stuId; //学号
        private double score; //分数

        public Student(string name,char sex ,int age, int stuId, double score) : base(name, sex, age)
        {
            this.StuId = stuId;
            this.Score = score;
            Console.WriteLine("我是Student类的构造函数,我被调用了");
        }

        public int StuId
        {
            get
            {
                return stuId;
            }

            set
            {
                stuId = value;
            }
        }

        public double Score
        {
            get
            {
                return score;
            }

            set
            {
                score = value;
            }
        }

        public void study()
        {
            Console.WriteLine("我是一名学生,我要学习各门功课。");
        }

        //使用关键字new隐藏父类成员。new创建对象后,隐藏从父类那里继承过来的同名成员。隐藏的后果就是子类调用不到父类的成员,所以尽量不要把子类成员名写得跟父类一样。
        public new void SayHello()
        {
            Console.WriteLine("大家好!我是学生类");
        }

    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp
{
    class Teacher: Person //Teacher类继承Person类
    {
        private int jobId; //教工号
        private double salary; //薪水
       
        public Teacher(string name, char sex, int age, int jobId, double salary) : base(name, sex, age)
        {
            this.JobId = jobId;
            this.Salary = salary;
            Console.WriteLine("我是Teacher类的构造函数,我被调用了");
        }

        public int JobId
        {
            get
            {
                return jobId;
            }
            set
            {
                jobId = value;
            }
        }

        public double Salary
        {
            get
            {
                return salary;
            }

            set
            {
                salary = value;
            }
        }

        public void work()
        {
            Console.WriteLine("我是老师,我的工作内容是教书。");
        }

        //使用关键字new隐藏父类成员。new创建对象后,隐藏从父类那里继承过来的同名成员。隐藏的后果就是子类调用不到父类的成员,所以尽量不要把子类成员名写得跟父类一样。
        public new void SayHello()
        {
            Console.WriteLine("大家好!我是教师类");
        }


    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            Student stu = new Student("盛婷婷",'女',18,1001,98.5);
            Console.WriteLine("姓名:{0},性别:{1},年龄:{2},学号:{3},成绩:{4}",stu.Name,stu.Sex,stu.Age,stu.StuId,stu.Score);
            stu.study();
            stu.SayHello();
            
            //如果此时仍然想访问基类的成员,则可以使用强制类型转换,把子类强制转换成基类,从而访问隐藏的基类成员。
            //((Person)stu).SayHello(); //输出了 大家好!我是人类
            
            Teacher tea = new Teacher("陈大文", '男', 40, 32, 6500);
            Console.WriteLine("姓名:{0},性别:{1},年龄:{2},教工号:{3},工资:{4}", tea.Name, tea.Sex, tea.Age, tea.JobId, tea.Salary);
            tea.work();
            tea.SayHello();
            
            Console.ReadKey();
        }
    }
}

运行结果:

image.png

类图

image.png

查看类图解决方法资源管理器-->项目-->右键-->查看-->查看类图

总结:

继承:父类(基类)、子类(派生类)

我们可能会在一些类中,写一些重复的成员,我们可以将这些重复的成员,单独的封装到一个类中,作为这些类的父类。

继承的特性:

(1)、继承的单根性:一个子类只能继承一个父类,不能同时继承多个父类。C#中,派生类只能从一个类中继承。C#不支持多重继承,通俗的说就是儿子只能有一个亲生父亲,不能同时拥有多个亲生父亲。C#可以继承多个接口。

(2)、继承的传递性:派生类从基类那里继承特性。派生类也可以作为其它类的基类。从一个基类派生出来的多层类形成了类的层次结构。通俗的说就是爷爷、爸爸、儿子的关系,儿子能访问爸爸、爷爷的公有成员,爸爸能访问爷爷的公有成员但不能访问儿子的公有成员。

class A

{

}

class B : A

{

}

//A是基类,B是派生类,一个类最多只允许从一个类中派生。

class C : B

{

}

//C还能继承B,充当B的派生类。


问:子类继承了父类,那么子类从父类那里继承过来了什么?

答:子类继承了父类的属性和方法,但子类并没有继承父类的私有字段。

问:子类有没有继承父类的构造函数和析构函数?

答:子类并没有继承父类的构造函数和析构函数,但是子类会默认的调用父类无参数的构造函数(用来创建父类对象,让子类可以使用父类中的成员。)所以如果在父类写了一个有参数的构造函数之后,那个默认的无参数的构造函数就被干掉了,因此子类就调用不到了,所以子类会报错。

解决方法:

方法一:在父类重新写一个无参数的构造函数。

方法二:一般都采用这种方法,在子类用显式的调用父类的构造函数,使用关键字 :base() 去调用父类的构造函数。

new关键字用途:

(1)、创建对象。

(2)、使用关键字new隐藏父类成员。new创建对象后,隐藏从父类那里继承过来的同名成员。隐藏的后果就是子类调用不到父类的成员,所以尽量不要把子类成员名写得跟父类一样。如果此时仍然想访问基类的成员,则可以使用强制类型转换,把子类强制转换成基类,从而访问隐藏的基类成员。例如:((Person)stu).SayHello();

子类的初始化顺序:

使用了继承之后,当我们初始化一个子类时,除了会调用子类的构造函数外,同时也会调用基类的构造函数。子类的初始化顺序如下:

(1)、初始化类的实例字段。

(2)、调用基类的构造函数,如果没有指明基类,则调用System.Object的构造函数。

(3)、调用子类的构造函数。

所有类的父类:System.Object

在C#中,所有的类都直接或间接继承System.Object类,如果定义的类没有指定任何基类,编译器就会自动把System.Object类当作它的基类。和其他类一样,System.Object类也定义了一组共有的成员,其定义如下:

public class Object
{
    //方法
    //构造函数
    public Object();
    
    //虚成员
    public virtual bool Equals(object obj);
    protected virtual void Finalze();
    public virtual int GetHashCode();
    public virtual string ToString();
    
    //实例成员
    public Type GetType();
    protected Object MemberwiseClone();
    
    //静态成员
    public static bool Equals(Object objA, Object objB);
    public static bool ReferenceEquals(Object objA, Object objB);
            
}


暗锚,解决锚点偏移

文章评论

    嘿,来试试登录吧!