c# 类的基础 (封装,继承,多态)、里式转换、接口

一,修饰符

类的访问修饰符2个,即 internal 和 public,默认为 internal。
类中成员的访问修饰符有 4 个,具体用法如下。

1) public:成员可以被任何代码访问。

2) private:成员仅能被同一个类中的代码访问,如果在类成员前未使用任何访问修饰 符,则默认为private。

3) internal:成员仅能被同一个项目中的代码访问。

4) protected:成员只能由类或派生类中的代码访问。

5)protected internal 

 部分类: partial  适用于多人合作写一个类   public partial class Dunk

 密封类:sealed   不能继承,但是可以继承别人。  public sealed class Dunk

 类不占用内存,而实例化为对象占用内存,static关键字定义为静态,常用于“工具类”

☆ 静态方法与实例方法的区别:静态方法只与类有关,不依赖于对象的存在而存在;实例方法则只能在对象实例化后才能使用。

 在修饰字段时通常用两个修饰符,即readonly (只读)和static (静态的)。
使用 readonly 修饰字段意味着只能读取该字段的值而不能给字段赋值。
使用 static 修饰的字段是静态字段,可以直接通过类名访问该字段。
需要注意的是常量不能使用 static 修饰符修饰。

 

 

 

一、2 属性用法:

namespace 类的基础
{
    class Program
    {
        static void Main(string[] args)
        {
            Tichets myt = new Tichets();
            myt.Price = 1000;
            
            Console.WriteLine($"{myt.Name}的价格是{myt.Price}"); //价格是100
            Console.ReadKey();
        }
    }

    public class Tichets //通过不同里程的票价来演示字段
    {
      
        //字段一般为private
        private readonly string _name; //readonly 只读
        private double _price;
        //定义属性方法,一般为public,本质是方法,对字段进行限制和保护,快捷键ctrl+r+e  
        public double Distance { get; set; }//使用自动属性,则不需要先设定字段。
        //在使用自动生成属性的方法时不能省略 get 访问器,如果不允许其他类访问属性值,则可以在 get 访问器前面加上访问修饰符 private
        public string Age { private get; set; }
        public string Name { get;  } = "yaoyue68"; //只读属性,去掉set即可
        
        public double Price //传统写法
        {
            get { return _price; }
            set
            {
                if (value>100)
                {
                   _price=100;   //属性的限定作用
                }

                value = _price;

                 }
        } 
    }

  

二:类构造函数、类的继承

 

namespace 类的基础
{
    class Program
    {
        static void Main(string[] args)
        {
            Mychild yq =new Mychild() ; //要对象new一个

            Console.ReadKey();
        }  
    }

    class Mychild:Father //只能单继承,方法为:,
    {
        public Mychild():base(4) //构造函数没有void返回值,默认先调用父类无参数构造函数,有参数时在base里面添加,
//可以理解为base()为父类构造函数,先执行 { Console.WriteLine("mychild类的构造函数开始执行了"); } } class Father {
public int b; public Father(int a) //父类构造函数有参数 {
this.b=a; Console.WriteLine($"我是father的构造函数,执行了{b}"); }
~Father() //析构函数,对象销毁时执行 { Console.WriteLine("我是father的析构函数"); } }

  执行结果:,注意执行顺序,先执行被继承类构造,然后是子类

 

 

 

三,this关键字

本类中如果构造函数是多重载时使用

    class Program
    {
        static void Main(string[] args)
        {
           Father yq = new Father("父亲",50,"男");

            Console.ReadKey();
        }
    }

  
    class Father
    {
        public Father(string name,int age)
        {
            Console.WriteLine($"我是{name}的构造函数,我{age}岁了");
        }
        public Father(string name, int age,string sex):this("父亲",50)
        {    //:this调用重载的构造函数,先执行this调用的构造函数,再运行本函数
            //相当于省略了这句Console.WriteLine($"我是{name}的构造函数,我{age}岁了"); 
           
            Console.WriteLine($"我是{sex}性");
        }
    }
}

 四、里氏转换

1)、子类可以赋值给父类。(配合is关键字判断是否可以转换)
(如:Person s = new Student();)
 2)、如果这个父类中装的是子类对象,那么可以将这个父类强转为子类对象。(小转大)
(如:Student p = (Student)s;)

子类对象可以调用父类中的成员,但是父类对象永远都只能调用自己的成员。

子类可以赋值给父类:如果有一个地方需要一个父类作为参数,我们可以给一个子类代替

 

  class Program
    {
        static void Main(string[] args)
        {
            //子类可以赋值给父类:如果有一个地方需要一个父类作为参数,我们可以给一个子类代替
            Father dg = new Children();
            dg.SayHello(); //dg装的是子类,但是仍是父类,父类对象永远都只能调用自己的成员

            //如果这个父类中装的是子类对象,那么可以将这个父类强转为子类对象。
            Father ss = new Children();
            Children fatherSwitch = (Children)ss;
            fatherSwitch.SayHello(); //变为子类

            //转换判断 is(bool) as(obj or null)
            if (dg is Children)
            {
                Console.WriteLine("我是父类装载的是子类");
            }
            else 
            {
                Console.WriteLine("");
            }

            //转换判断 as(obj or null) 
            Children a = ss as Children;//ss转换children成功返回obj,否则null


            Console.ReadKey();
        }
    }

    public class Father
    {
        public string a = "我是父类属性";
        public void SayHello()
        {
            Console.WriteLine("我是父类");
        }      
    }

  public class Children:Father
    {
        public string b = "我是子类属性";
        public void SayHello()
        {
            Console.WriteLine("我是子类");
        }
    }

  练习:随机执行不同子类方法

        static void Main(string[] args)
        {
            Teacher li = new Teacher();
            Student wang = new Student();
            Repoter zhang = new Repoter();
            //创建父类数组用来装载子类
            People[] MyChildren = new People[3];
            //for循环装载子类
            for (int i = 0; i < MyChildren.Length; i++)
            {
              
                Random rm = new Random();
                int rms = rm.Next(0, 3); //random随机数短时间内相同
                switch (rms)
                {
                    case 0 :MyChildren[i] = new Teacher();
                        break;
                    case 1:
                        MyChildren[i] = new Student();
                        break;
                    case 2:
                        MyChildren[i] = new Repoter();
                        break;
                }
               
            }
            for (int i = 0; i <MyChildren.Length; i++)
            {
                if (MyChildren[i] is Student ) //is判断
                {
                    ((Student)MyChildren[i]).SayHello();//注意写法
                }
                else if(MyChildren[i] is Teacher)
                {
                    ((Teacher)MyChildren[i]).SayHello();
                }
                else
                {
                    ((Repoter)MyChildren[i]).SayHello();
                }
            }
            Console.ReadKey();
        }
    }
public class People { public void SayHello() { Console.WriteLine("我是父类"); } } public class Teacher:People { public new void SayHello() //new显式隐藏父类同名函数,即覆盖 { Console.WriteLine("我是教师"); } } public class Student : People { public new void SayHello() { Console.WriteLine("我是学生"); } } public class Repoter: People { public new void SayHello() { Console.WriteLine("我是记者"); } }

五、多态:

让一个父类对象表达出多个子类的属性和方法

3种实现方法:1.虚方法 2.抽象类 3.接口

 

什么时候用抽象类:能抽象出一个父类+共同方法+实现不了方法功能

什么时候用虚方法:能抽象出一个父类+父类要对象化+方法可以实现功能

什么时候用接口:    不能抽象出父类+有共同的功能

 

 (一)虚方法:在子类中调用父类方法,base.sayhello();

 class Program
    {
        static void Main(string[] args)
        {
            Student sd = new Student();
            Teacher tc = new Teacher();
            //创建父类数组,放入
            Person[] pr = new Person[] { sd, tc };
            //pr类型为person[]类型,应为父类的sayhello,
            //使用虚方法后,子类覆盖重写同名函数实现多态,即同一个行为在不同子类中表现不同(动物的叫声在羊和狗身上不同)
            pr[0].Sayhello();//学生的hello
            pr[1].Sayhello();//老师的hello
            Console.ReadKey();
        }
    }

    public class Person
    {
        public virtual void Sayhello() //父类关键字 virtual 虚方法
        {
            Console.WriteLine("父类的hello");
        }
    }
    public class Student : Person
    {
        public override void Sayhello() //子类关键字 override 覆盖重写实现多态
        {
            Console.WriteLine("学生的hello");
        }

    }
    public class Teacher : Person
    {
        public override void Sayhello()
        {
            Console.WriteLine("老师的hello");
        }
    }

(二)抽象类:一般专门用来继承用,不创建实例,“类名.方法”也不能调用

 

抽象类的使用场景:
如果一个类设计的目点是用来被其它类继承的,它代表一类对象的所具有的公共属性或方法,那个这个类就应该设置为抽象类。
在实现接口时,常写一个抽象类,来实现接口中的某些子类中所需的通用方法,接着在编写各个子类时,即可继承该抽象类来用。省去在每一个都要实现通用的方法的困扰。

 

        抽象方法/成员:给子类一个空的样板,子类必须填充实现

  虚方法和抽象类区别: 父类不知道怎么实现子类方法,用抽象类,知道怎么实现用虚方法;父类不需要实例化用抽象类,需要用虚方法。

       接口和抽象类不允许创建实例对象

 

 

   class Program
    {
        static void Main(string[] args)
        {
            Person a = new Student();//多态让父类表现多种子类特性
            a.Sayhello(); //由于override覆写,所以为子类student方法
           
            Console.ReadKey();
        }
    }
    public abstract class Person //abstract抽象类
    {
        public abstract void Sayhello();  //注意写法
    }
    public class Student : Person
    {
        public override void Sayhello() //必须有override覆写
        {
            Console.WriteLine("学生hello");
        }
    }

 

 多态练习: 求圆面积和周长、正方形面积和周长

class Program
    {
        static void Main(string[] args)
        {
            Circle c = new Circle(2.5);
            double s=c.GetArea();

            Console.WriteLine(s);
            Console.ReadKey();
        }
    }
    public abstract class Shape
    {
        public abstract double GetArea();
        public abstract double GetPrimeter();

    }

    public class Circle : Shape
    {
        private double _r;
        
            //构造函数传入半径r
       public Circle(double r)
        {
            this.R = r;
        }

        public double R { get => _r; set => _r = value; }

        public override double GetArea()
        {
            return Math.PI *this. R * this.R;
        }

        public override double GetPrimeter()
        {
            return 2 * Math.PI * this.R;
        }
    }

  正方形省略....

 总结:

 

posted @ 2021-02-19 11:15  遥月  阅读(468)  评论(0)    收藏  举报