C#中封装 继承 多态 接口 抽象类

目录

1.封装

2.继承

3.多态

1.静态多态性

1.函数重载

2.运算符重载

3.可重载和不可重载运算符

2.动态多态性

1.虚拟(virtual)和重写(override)

2.隐藏

3.抽象类

4.接口

参考


1.封装

封装 被定义为"把一个或多个项目封闭在一个物理的或者逻辑的包中"。在面向对象程序设计方法论中,封装是为了防止对实现细节的访问。

C# 封装根据具体的需要,设置使用者的访问权限,并通过 访问修饰符 来实现。

一个 访问修饰符 定义了一个类成员的范围和可见性。C# 支持的访问修饰符如下所示:

  • public:所有对象都可以访问;
  • private:对象本身在对象内部可以访问;
  • protected:只有该类对象及其子类对象可以访问
  • internal:同一个程序集的对象可以访问;
  • protected internal:访问限于当前程序集或派生自包含类的类型。

2.继承

派生类格式

属性 类修饰符 class 派生类名:基类名{
    类体
}

子类不能继承基类中定义的private方法,只能继承基类的public成员或者protected成员。

基类的初始化会首先调用基类的构造函数再调用子类的构造函数,子类中如果有有参的构造函数,会默认调用父类中无参的构造函数,此时,要在父类中定义一个无参的构造函数。如果想调用父类中有参的构造函数,要在子类中构造函数后面加":base(继承父类的参数)",同时,在子类中构造函数中写自己独有的属性即可。

如果子类中要写一个函数覆盖父类中的某个函数,则在定义时用new,不能用override.


 class Program
    {
        static void Main(string[] args)
        {
            employee employe = new employee("党小春",25,"福德村6组",1000);
            employe.Display();
            employee employe2 = new employee();
            employe2.Display();
            //Console.WriteLine(employe.Age);
            Console.ReadKey();
           
        }
    }
    public class Person
    {
        public  string Name;
        public  int Age;
        public Person(string name,int age)
        {
            Name = name;
            Age = age;
        }
        public Person()
        {

        }
        public void Display()
        {
            Console.WriteLine("姓名:{0} 年龄:{1}", Name, Age);
        }
    }
    class employee : Person  //Person是基类
    {
        private string department;
        private decimal salary;
        public employee():base()
        {

        }
        public employee(string name, int age, string depmt, decimal sal)
            : base(name, age)
        {//base的第一种用法,根据参数调用指定基类构造函数,注意参数的传递
            department = depmt;
            salary = sal;
        }
        public new void Display()
        {//覆盖基类Display()方法,注意new,不可用override
            base.Display();  //base的第二种用法,访问基类被覆盖的方法
            Console.WriteLine("部门:{0}   薪水:{1}", department, salary);
        }
    }

 若B继承自A,也可以使用强制转换操作将其转换为A 对象。如:

  A b = (A)new B();或者 A b = new B();此时,B对象将被限制为A 对象的数据和行为,而无法再访问B对象中的数据和行为,除非A中的方法被B重写,将会访问B 的方法。将B强制转换为A后,还可以将A重新转换为B,但是,并非A的所有实例在任何情况下都可强制转换为B,只有实际上是B的实例的那些实例才可以强制转换为B

 如下所示,满足上述文字描述的

static void Main(string[] args)
        {
            Person employe = new employee("党小春",25,"福德村6组",1000);
            employe.Display();
            employee e = (employee)employe;
            e.Display();
            //employe.Display();
            //employee employe2 = new employee();
            //employe2.Display();
            ////Console.WriteLine(employe.Age);
            Console.ReadKey();
           
        }

3.多态

同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果,这就是多态性。实际上就是同一个类型的实例调用“相同”的方法,产生的结果是不同的。这里的“相同”打上双引号是因为这里的相同的方法仅仅是看上去相同的方法,实际上它们调用的方法是不同的。 

多态性可以是静态的或动态的。在静态多态性中,函数的响应是在编译时发生的。在动态多态性中,函数的响应是在运行时发生的。

1.静态多态性

在编译时,函数和对象的连接机制被称为早期绑定,也被称为静态绑定。C# 提供了两种技术来实现静态多态性。分别为:

1.函数重载

在同一个作用域(一般指一个类)的两个或多个方法函数名相同,参数列表不同的方法叫做重载,它们有三个特点(俗称两必须一可以):

  • 方法名必须相同
  • 参数列表必须不相同
  • 返回值类型可以不相同

2.运算符重载

重载运算符是具有特殊名称的函数,是通过关键字 operator 后跟运算符的符号来定义的。与其他函数一样,重载运算符有返回类型和参数列表。

用户自定义的操作符要写public和static

class Program
    {
        static void Main(string[] args)
        {
            Box a = new Box(2, 3.1);
            Box b = new Box(3, 5.4);
            Box c = a + b;
            Console.WriteLine("c.length={0},c.width={1}", c.length, c.width);
            Console.ReadKey();

           
        }
        }
    }
    public class Box
    {
        public int length;
        public double width;
        public Box()
        {

        }
        public Box(int len,double wid)
        {
            length = len;
            width = wid;
        }
        public static Box operator+(Box a,Box b)
        {
            Box box = new Box();
            box.length = a.length + b.length;
            box.width = a.width + b.width;
            return box;

        }

    }

3.可重载和不可重载运算符

下表描述了 C# 中运算符重载的能力:

运算符 描述
+, -, !, ~, ++, -- 这些一元运算符只有一个操作数,且可以被重载。
+, -, *, /, % 这些二元运算符带有两个操作数,且可以被重载。
==, !=, <, >, <=, >= 这些比较运算符可以被重载。
&&, || 这些条件逻辑运算符不能被直接重载。
+=, -=, *=, /=, %= 这些赋值运算符不能被重载。
=, ., ?:, ->, new, is, sizeof, typeof 这些运算符不能被重载。

2.动态多态性

动态多态性是通过 抽象类 和 虚方法 实现的。

1.虚拟(virtual)和重写(override)

c#中,如果基类的某个功能不满足要求,可以在子类中重写基类的方法实现新的功能,子类中为满足自己的需要来重复定义某个方法的不同实现,需要用override关键字,被重写的方法必须是虚方法,用的是virtual关键字。它的特点是(三个相同):

  • 相同的方法名
  • 相同的参数列表
  • 相同的返回值。
class Program
    {
        static void Main(string[] args)
        {

            employee e = new employee();
            e.Display();
            Console.ReadKey();


        }

    }
    public class Person
    {
        public string Name;
        public int Age;
        public Person(string name, int age)
        {
            Name = name;
            Age = age;
        }
        public Person()
        {

        }
        public virtual void Display()
        {
            Console.WriteLine("姓名:{0} 年龄:{1}", Name, Age);
        }
    }
    class employee : Person  //Person是基类
    {
        private string department;
        private decimal salary;
        public employee()
            : base()
        {

        }
        public employee(string name, int age, string depmt, decimal sal)
            : base(name, age)
        {//base的第一种用法,根据参数调用指定基类构造函数,注意参数的传递
            department = depmt;
            salary = sal;
        }
        /// 
        ///  重写Display方法
        /// 
        public override void Display()
        {//覆盖基类Display()方法,注意new,不可用override
            //base.Display();  //base的第二种用法,访问基类被覆盖的方法
            Console.WriteLine("部门:{0}   薪水:{1}", department, salary);
        }
    }

注意:(1)虚拟方法不能声明 为静态的。因为静态的方法是应用在类一层次的,而面向对象的多态性只能在对象上运作,所以无法在类中使用。此外,override,abstract也不能跟static共存.

       (2)virtual 不能和private 一起使用,否则无法在子类中重写。

       (3)重写方法的名称、参数个数、类型以及返回值都必须和虚拟方法一致。

2.隐藏

只要在子类的方法或属性前声明为new,就可以隐藏基类的方法或属性。理解:新方法把老方法(相对于子类)隐藏,但老方法仍可见。

注意:(1)隐藏方法不但可以隐藏基类中的虚方法,而且也可以隐藏基类中的非虚方法。

           (2)隐藏方法中父类的实例调用父类的方法,子类的实例调用子类的方法。

           (3)和上一条对比:重写方法中子类的变量调用子类重写的方法,父类的变量要看这个父类引用的是子类的实例还是本身的实例,如果引用的是父类的实例那么调用基类的方法,如果引用的是派生类的实例则调用派生类的方法。

什么时候用隐藏呢:如开发人员A需要重新设计基类中的某个方法,该基类是一年前由另一组开发人员设计的,并且已经交给用户使用,可是原来的开发人员在方法前没有加virtual关键字,但又不允许修改原来的程序,这是无法用override重写基类的方法,这是就需要隐藏基类的方法。

3.抽象类

若类中的方法或属性为abstract,类必须用abstract修饰。只能用作基类,抽象方法没有实现代码(无大括号!)

class Program
    {
        static void Main(string[] args)
        {

            B b = new B();
            b.print();
            Console.ReadKey();


        }

    }
    public abstract class A
    {
        public abstract void print();
    }
    public class B : A
    {
        public override void print()
        {
            Console.WriteLine("print!");
        }
    }

当从抽象类派生非抽象类时,非抽象类必须实现抽象类的所有(必须是所有!)抽象成员,当然,如果继承抽象类的也是抽象类就不必实现其抽象成员,由最后一个非抽象类实现。

抽象类的一些规则:

  • 您不能创建一个抽象类的实例。
  • 您不能在一个抽象类外部声明一个抽象方法。
  • 通过在类定义前面放置关键字 sealed,可以将类声明为密封类。当一个类被声明为 sealed 时,它不能被继承。抽象类不能被声明为 sealed。

4.接口

接口定义了所有类继承接口时应遵循的语法合同。接口定义了语法合同 "是什么" 部分,派生类定义了语法合同 "怎么做" 部分。

接口定义了属性、方法和事件,这些都是接口的成员。接口只包含了成员的声明。成员的定义是派生类的责任。接口提供了派生类应遵循的标准结构。接口使得实现接口的类或结构在形式上保持一致。

interface IMyInterface
{
    void MethodToImplement();
}

如果一个接口继承其他接口,那么实现类或结构就需要实现所有接口的成员。

参考

https://www.cnblogs.com/HansenChen/archive/2012/03/09/2388247.html

https://www.cnblogs.com/zhangkai2237/archive/2012/12/20/2826734.html

https://www.runoob.com/csharp/csharp-interface.html

你可能感兴趣的:(C#中封装 继承 多态 接口 抽象类)