C#之面向对象

面向对象

面向对象三大特征:封装、继承、多态

封装:类对外部提供public方法,调用者不用关心类内部的运行机制

继承:子类继承自父类,子类可以继承父类所有非private成员,实现代码重用;

多态:子类中可以覆盖(override)父类中的virtual方法;父类类型的变量可以指向子类类型的对象,调用的方法如果子类override了,则调用的是子类的实现(一个方法在不同环境下不同的表现形态)。

一、封装

1.封装的具体表现

(1)属性封装字段

public class Person
    {
        private int _id = -1;

        public int Id
        {
            get
            {
                return _id;
            }
            set
            {
                _id = value;
            }
        }
    }

对内部使用的字段是_id,外部使用的是Id属性。对属性名称进行修改,不需要修改_id名称。

(2)方法的多个参数封装成一个对象

(3)将一堆代码封装到一个方法中

(4)将一些功能封装到一个类中

(5)将一些具有相同功能的代码封装到一个程序集中(dll、exe),并且对外提供统一的访问接口(方法名、属性名等)

二、继承(类与类之间的关系):一个类继承另一个类,那么这个类也就有了另一个类的非private成员

1.判断一个继承是否合理?(子类 is a 父类)

比如:香蕉是水果吗?是。香蕉类继承水果类

2.继承的好处

(1)代码重用

(2)多态

里氏替换原则:需要一个父类类型时,给一个子类对象是可以的。

里氏替换原则就是为了多态=>多态就是为了增加程序的可扩展性,灵活性。

public class Person
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

    public class Student:Person
    {
        public string StuId { get; set; }
    }

调用部分:
Person p1 = new Student();

因为有了继承,便有了里氏替换原则,有了里氏替换原则,便有了多态

 3.继承中的构造函数问题

public class Person
    {
        public Person(int id,string name)
        {
            this.Id = id;
            this.Name = name;
        }
        public int Id { get; set; }
        public string Name { get; set; }
    }

    public class Student:Person
    {
        public string StuId { get; set; }

        public Student(int id, string name, string stuid)
        {
            this.Id = id;
            this.Name = name;
            this.StuId = stuid;
        }
    }

 当一个子类继承父类以后,该子类中的所有构造函数默认情况下,在自己被调用之前都会先调用一次父类的无参构造函数,如果此时父类中没有无参的构造函数,则提示报错!

解决方法一:在父类中添加一个无参构造函数

解决方法二:在子类的构造函数后面通过:base()的方式,明确指定要调用父类中的那个构造函数。

public class Person
    {
        public Person(int id,string name)
        {
            this.Id = id;
            this.Name = name;
        }
        public int Id { get; set; }
        public string Name { get; set; }
    }

    public class Student:Person
    {
        public string StuId { get; set; }

        public Student(int id, string name, string stuid):base(id,name)
        {
            this.StuId = stuid;
        }
    }

 :base()表示调用父类的构造函数

三、多态

1.多态的三种表现形态

  (1)虚方法

  (2)继承

  (3)接口

2.多态实行开放封闭原则:对修改封闭,对扩展开放

3.多态的作用:把不同的子类对象当作父类来看,可以屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程,以适应需求的不断变化。

4.实现多态的三种方法的区别:

  (1)虚方法是实例类,具有默认实现

  (2)抽象方法没有默认实现,除非子类也是一个抽象类

  (3)接口存在是为了解决:

    1.类的多继承问题

    2.类继承以后体积庞大的问题

 四、接口

接口是一种规范、协议。约定好遵守某种规范就可以写通用的代码了。

接口存在的意义就是为了多态

接口的存在解决了:

  (1)类的单继承问题

  (2)类继承以后体积庞大的问题

1.接口里面只能包含方法:

  (1)方法

  (2)属性

  (3)索引器

  (4)事件

  因为属性,索引器,事件本质上都是方法。【字段不能定义在接口中】

2.接口中的所有成员都不能显示的写任何访问修饰符,默认是public的访问修饰符

3.方法,属性,索引器在接口中的定义方式

public interface DefinitionInterface
    {
        /// <summary>
        /// 定义方法
        /// </summary>
        void SayHello();

        /// <summary>
        /// 定义返回值是string类型的方法
        /// </summary>
        /// <returns></returns>
        string Eat();
        /// <summary>
        /// 定义属性
        /// </summary>
        string Name
        {
            get;
            set;
        }
        /// <summary>
        /// 定义索引器
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        string this[int index]
        {
            get;
            set;
        }
    }

4.接口不能被实例化,就是为了让子类来实现的

5.接口中的成员,子类必须实现

五、虚方法与抽象方法

1.虚方法

  (1)具有父子类关系

  (2)父类需要重写的方法添加virtual

  (3)子类重写的方法添加override

class Program
    {
        static void Main(string[] args)
        {
            Person p1 = new Student();
            p1.SayHello();
            Console.ReadKey();
        }
    }

    public class Person
    {
        public string Name { get; set; }
        public virtual void SayHello()
        {
            Console.WriteLine("人类说Hello");
        }
    }

    public class Student:Person
    {
        public override void SayHello()
        {
            Console.WriteLine("学生说Hello");
        }
    }

Student类重写了子类的SayHello方法,那么在调用p1.SayHello();方法时就会调用重写的方法

2.抽象方法

  (1)抽象类中可以有实例成员,也可以有抽象成员

  (2)抽象成员必须包含在抽象类中

  (3)抽象成员不能有任何实现

  (4)抽象类不能用来实例化对象,只能被继承

  (5)抽象成员子类继承以后必须重写override,除非子类也是一个抽象类

public abstract class Person
    {
        public string Name { get; set; }

        public abstract void SayHello();
        
    }

    public class Student:Person
    {
        public override void SayHello()
        {
            Console.WriteLine("Student类重写Person类");
        }
    }

虚方法和抽象方法的区别:

  (1)虚方法有默认实现,抽象方法没有默认实现。

  (2)如果虚方法不重写,那么就调用父类的方法;抽象方法中子类必须实现抽象方法,除非子类也是一个抽象方法。

六、静态类

1.静态类的特点

  (1)静态类中只能有静态成员。

  (2)静态成员不是必须写在静态类中。

  (3)在程序中的任何一个地方访问该静态成员,其实都访问的是同一块内存。

  (4)静态成员的数据直到程序退出以后才释放资源;实例对象只要使用完毕就可以执行垃圾回收了。

2.静态类和静态成员要使用static修饰

3.静态构造函数

  (1)类中的静态成员,在第一次使用静态成员的时候进行初始化

  (2)静态构造函数不能手动来调用,而是在第一次使用静态

七、访问修饰符

1.访问修饰符

  (1)private 只能在当前类的内部可以访问

  (2)protected 只能在当前类内部以及所有子类的内部可以访问

  (3)internal 在当前程序集内部访问

  (4)public 任何地方都可以访问

2.命名空间中的访问修饰符只能是public或internal,不能是其他访问修饰符(类不加访问修饰符默认是internal)

3.类的成员变量,如果不写访问修饰符默认是private

4.访问级别约束:

  (1)子类的访问级别不能比父类的高(会暴露父类的成员)

  (2)类中属性或字段的访问级别不能比所对应的类型访问级别高

  (3)方法的访问级别不能比方法的参数和返回值的访问级别高

原文地址:https://www.cnblogs.com/fengjiqiang123/p/11911835.html