网易云课堂C#面对对象编程ONE

1.抽象类和抽象方法

abstract和virtual  

https://blog.csdn.net/jiangxinyu/article/details/6570232

抽象类的存在目的就是必须被继承。

无法创建抽象类的实例,抽象类不能被实例化。派生类中用override关键字实现。

抽象类比virtual更进一步,更加抽象

using System;
using System.Collections.Generic;

namespace test1
{
  abstract public class Pet//抽象方法必须在抽象类中
    {
        public string _name;//重命名变量,也叫重构,一般下划线_表示私有
        public Pet(string name)
        {
           _name = name;
        }
        abstract public void Speak();//抽象方法不需要实现
      
    }
    public class Dog : Pet
    {
        
        public Dog(string Name) : base(Name)
        {
           
        }
        override public void Speak()
        {
            Console.WriteLine(_name+"汪汪汪");
        }
    }
    public class Cat : Pet
    {
        public Cat(string P) : base(P)//调用基类中的构造函数初始化Name,更加简洁
        {
           
        }
        override public void Speak()
        {
            Console.WriteLine(_name + "喵喵喵");
        }
    }
    class Program
    {
        public static void Main(string[] args)
        {
            Pet[] pets = new Pet[] { new Dog("小狗"), new Cat("小猫") };
            foreach( Pet pet in pets)//foreach循环   Pet是数据类型,pet是foreach的迭代变量,读取集合中每一个元素
            {
                pet.Speak();
            }
            Console.ReadKey();
        }
    }
}

2.密闭类和密闭方法

有些类不希望其他人通过继承来修改,如string类就用密闭类用sealed修饰。

有些方法不希望其他人重写该方法,就用密闭方法。、

如果一个基类方法不希望子类对其重写,可以不声明为virtual和abstract。如果某个派生类方法不希望其子类对其重写,则同时使用sealed和override进行修饰。 

3.接口

接口是指定一组函数成员,而不实现他们的引用类型(有点像完全没有普通函数和数据的抽象类,比抽象类更加抽象。是引用类型,不是值类型。)

接口用来被实现

有{}就代表有实现

接口的强大之处在于类可以同时继承多个接口。当派生类既继承基类也继承接口时,派生类冒号之后先写基类,在写接口。

interface ICatchMice
    {
        void CatchMice();//默认public,不能添加访问修饰符
    }
   interface IClimb
    {
        void Climb();
    }
    abstract public class Pet
    {
       public string name;
       abstract public void Speak();
       public Pet(string Name)
        {
            name = Name;
        }
    }
    class Cat : Pet,ICatchMice,IClimb//实现类继承和接口继承,接口是引用类型
    {
        public Cat(string Name) : base(Name)
        {

        }
        public void CatchMice() 
        {
            Console.WriteLine(name+"catch a mouse");
        }
        public void Climb()
        {
            Console.WriteLine("爬上树");
        }
        public override void Speak()
        {
            Console.WriteLine("喵喵喵 ");
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Cat c = new Cat("小黑");
            ICatchMice ic = (ICatchMice)c;//接口是引用类型,这里将C强制转化为IcatchMice引用类型。
            c.CatchMice();//通过对象调用,可以调用对象所定义的函数
            ic.CatchMice();//通过接口调用,只能调用接口所定义的函数,即CatchMice有两种实现方法,实现的方式不同
            c.Speak();
            IClimb tree = (IClimb)c;
            tree.Climb();
            Console.ReadKey();
        }
    }

4.结构和类:

结构时值类型(在栈中),类是引用类型(在堆中)

结构不支持继承,但可以实现接口。类支持继承也支持接口

结构不能定义默认构造函数,编译器会自定义

结构的使用场合:由于分配内存快,作用域结束立即被删除,不需要垃圾回收,用于小型的数据结构,但值类型传递过程中会赋值,应该使用ref即引用类型参数来提高效率。即有些参数等用完即不再需要了,就最好用结构。

类:用于其他需要继承体系的场合。

C#中结构的使用:

  struct Rectgle
    {
        public double length;
        public double width;
        public Rectgle(double x,double y)
        {
            length = x;
            width = y;
        }
        public double RectArea()
        {
            return length * width;
        }
    }
    class program
    {
        static void Main(string[] args)
        {
            Rectgle rect;
            rect.length = 12;
            rect.width = 5;
            Console.WriteLine(rect.RectArea());
            Rectgle rect2 = new Rectgle(12, 8);//实例化结构
            Console.WriteLine(rect.RectArea());
            Console.ReadKey();
        } 
    }

5.所谓用new实例化类,结构,其实是用new创建对象,面对对象编程中只有创建了对象,才能进行操作。

6.静态类和静态成员。

静态成员:

 标识为static的字段,方法,属性,构造函数,事件,就是静态成员。

静态成员将被类的所有实例共享,所有实例都访问同一内存位置,即公共的成员。

一个类中的静态成员和实例成员是分开存储的。

静态成员的访问可以直接通过类名访问,而一般的成员则需要通过对象访问,即用new创建一个对象,然后通过对象访问。

静态成员的生存期,静态成员独立于任何的实例,且即使没有实例也可以访问,其初始化语句在静态成员使用之前调用。

静态函数成员:

静态函数也独立于任何实例,没有实例也可以访问,静态函数不能访问实例成员,仅可以访问其他静态成员,但实例成员可以访问静态函数

静态构造函数:

静态构造函数专门用于初始化静态字段。

在引用任何静态成员之前调用,在创建任何实例之前调用。

a.与类同名,使用static,无参数,无访问修饰符

class Dog
{
static int num;
static Dog(){num=0}
}

b.

public class Pet
    {
        static int Num;
        string name;
        public Pet(string Name)
        {
            name = Name;
            ++Num;//每创建一个Pet对象,此构造函数调用一次,Num加1
        }
      static public  void PrintNum()
        {
            Console.WriteLine(Num);
        }
    }
    class program
    {
        static void Main(string[] args)
        {
            Pet dog = new Pet("小黑");
            Pet cat = new Pet("大黄");
            Pet.PrintNum();//静态函数直接类名加方法名调用。
            Console.ReadKey();

        }
    }

静态类:

静态类不能创建实例,且默认是密封的,不能被继承。

若类只包含静态方法和属性且标识为static则为静态类。

可以为静态类构造静态构造函数。

静态类主要用于基础类库(如数学库)和扩展方法。

扩展方法: 

a.直接修改源代码,添加新方法

b.如果不能修改源代码但也不是密闭的类,则使用派生子类扩展

c.如果以上条件都不满足,可以使用静态类扩展的方法。

静态类的扩展方法:

a.

 public class Dog//假设Dog这个类无法更改了
    {

    }
    static class PetGuide
    {
        public  static void HowToFeed(this Dog dog)//静态类传入dog对象
        {

        }
    }
    class program
    {
        static void Main(string[] args)
        {
            Dog dog = new Dog();
            dog.HowToFeed();//创建Dog类的实例对象,却能够通过Dog类访问HowToFeed方法
        }
    }

b.静态类扩展要求

扩展方法必须在静态类中定义,扩展方法本身为static方法,扩展方法的第一个参数类型为this+类名。

7.重载操作符:

装箱和拆箱:装箱即根据值类型的值,在堆上创建一个完整的引用类型对象(一般为Object类型),并返回对象的引用,是一种隐式转换(即将值类型转换成引用类型)。转化成引用类型后可以进行统一的操作(例作为函数的参数)和统一的存储(object[])

装箱的示例:

    int i = 3;
    object oi = null;
    oi=i;//在堆中创建了新的对象,oi指向该对象,其包含的值为3

装箱的本质:

即在堆上创建了引用类型的副本,新创建的引用类型和原来的值类型相互独立。装箱后改变其中一个,另一个不发生变化。

拆箱:将装箱后的对象转换回值类型的过程,是一种显示转换。

int i=3;
object oi=i;
int j=(int)oi;


自定义转换:有点不理解?

为自己的结构或者类定义显式或者隐式的转换。使结构和类变成一个预期的相关类型。

隐式转换:implicit operator

abstract public class Pet
    {
        public string _name;//重命名变量,也叫重构,一般下划线_表示私有
        public Pet(string name)
        {
            _name = name;
        }
        abstract public void Speak();

    }
    public class Dog : Pet
    {

        public Dog(string Name) : base(Name)
        {

        }
        override public void Speak()
        {
            Console.WriteLine(_name + "汪汪汪");
        }
        public static implicit operator Cat(Dog dog)//隐式转换,没有函数名,其中的Cat是返回值类型,将类Dog转化为Cat
        {
            return new Cat(dog._name);//返回一个Cat对象,将狗的名字给Cat
        }
    }
    public class Cat : Pet
    {
        public Cat(string P) : base(P)//调用基类中的构造函数初始化Name,更加简洁
        {

        }
        override public void Speak()
        {
            Console.WriteLine(_name + "喵喵喵");
        }
    }
    class Program
    {
        public static void Main(string[] args)
        {
            Dog dog = new Dog("小狗");
            Cat cat = dog;//这里的dog相当于new Cat(dog.name)
            cat.Speak();//运行发现猫咪的名字变为Jack,叫声为喵喵喵。调用的方法为Cat类中的Speak
            Console.ReadKey();
        }
    }

显式转换:explicit operator

abstract public class Pet
    {
        public string _name;//重命名变量,也叫重构,一般下划线_表示私有
        public Pet(string name)
        {
            _name = name;
        }
        abstract public void Speak();

    }
    public class Dog : Pet
    {

        public Dog(string Name) : base(Name)
        {

        }
        override public void Speak()
        {
            Console.WriteLine(_name + "汪汪汪");
        }
        
    }
    public class Cat : Pet
    {
        public Cat(string P) : base(P)//调用基类中的构造函数初始化Name,更加简洁
        {

        }
        override public void Speak()
        {
            Console.WriteLine(_name + "喵喵喵");
        }
        public static explicit operator Dog(Cat cat)//显式,没有函数名,其中的Dog是返回值类型,将类Cat转化为Dog
        {
            return new Dog(cat._name);//返回一个Dog对象,将猫的名字给Dog
        }
    }
    class Program
    {
        public static void Main(string[] args)
        {
            Cat cat = new Cat("小猫");
            Dog dog=(Dog)cat;//显式转换,这里的(Dog)cat相当于new Dog(cat.name)
            dog.Speak();//运行发现狗的名字变为Jack,叫声为汪汪汪。调用的方法为Dog类中的Speak
            Console.ReadKey();
        }
    }
重载运算符:这部分也没有特别理解

利用现有的某种运算符,针对自定义类或者结构,定义某种运算操作即利用原有的运算符重新定义了一种运算操作。利用现有的运算符,简化自定义类型的操作。最好是该运算符和该操作,具有一定的相关性。比如要类A和类B结合产生C,一般需要定义一个类进行操作,但更简单的是用A+B=C

public static  Dog  operator +(Dog male,Dog female)//重载加法运算 Dog是返回值。+为二元操作符
{
...
return new Dog();
}

重载运算符中,一元运算符操作数必须是类或者结构。二元操作符两个操作数至少有一个是类或者结构。

重载运算符不能够做什么:

创建新运算符,改变运算符语法,改变运算符的优先级和结合性。

例如重载++一元运算符:

abstract public class Pet
    {
        public string _name;
        public int _age;
        public Pet(string name)
        {
            _name = name;
            _age = 0;
        }
        abstract public void Speak();
        public static Pet operator ++(Pet pet)//重载运算符++,使++的操作定义发生改变,其中Pet是返回值类型
        {
            ++pet._age;
            return pet;//此时返回的pet中_age已经改变了
        }
        public void ShowAge()
        {
            Console.WriteLine(_name + _age+"岁");
        }
        }


       public class Dog : Pet
        {

        public Dog(string Name) : base(Name)
        {

        }
        override public void Speak()
        {
            Console.WriteLine(_name + "汪汪汪");
        }

    } 


    public class Cat : Pet
    {
        public Cat(string P) : base(P)//调用基类中的构造函数初始化_name,更加简洁
        {

        }
        override public void Speak()
        {
            Console.WriteLine(_name + "喵喵喵");
        }
    }
    class Program
    {
        public static void Main(string[] args)
        {
            //Pet[] pets = new Pet[] { new Dog("小狗"), new Cat("小猫") };
            //for (int i=0;i<pets.Length;++i)
            // {
            //  pets[i]++;                  //_age改变
            //    pets[i].ShowAge();
            // }
上面的一段相当于
            Pet dog=new Dog("小狗");
            dog++;
            dog.ShowAge();
            Pet cat = new Cat("小猫");
            cat++;
            cat.ShowAge();
            Console.ReadKey();
        }
    }



8.泛型:

a.泛型类

泛型类是一个模子,装入类型的材料,就可以塑造出想要的产品。即将具体的类的类型和相关参数注入泛型类,就可以得到自己想要的具体的类。(相当于一个实参,实参是类类型或内置类型)

例如

class Cage<T>{                //这里创建一个Cage的模型,T是类类型(可以说是类型实参),T是占位符作用:会被替换掉
T[] petsArray;
public void PutIn(T pet){...}
public T TakeOut(int index){...}
}

为什么用泛型类:

减小工作量,用基类和接口也可以作为模板的作用,但有弊端,使类型太宽泛,什么都可以由此派生即放入,需要显式的转换类型,并且判断其真实类型是什么。而泛型类只有有需要的类型才能被实例化。易于维护,修改模板,所有实例都将改变。

实例化:

class Cage<T>{...}//泛型类的声明,声明Cage<T>泛型类
Cage<Dog> dogCage;//Cage<Dog>类型的引用,即创建名称为dogCage的Cage<Dog>类型
dogCage=new Cage<Dog>();//构造实例

例子:

 abstract public class Pet
    {
        public string _name;//重命名变量,也叫重构,一般下划线_表示私有
        public Pet(string name)
        {
            _name = name;
        }
        abstract public void Speak();

    }
    public class Dog : Pet
    {

        public Dog(string Name) : base(Name)
        {

        }
        override public void Speak()
        {
            Console.WriteLine(_name + "汪汪汪");
        }
    }
 public class Cage<T>
    {
        T[] array;//T类型数组,名称为array
        readonly int Size;
        int num;
        public Cage(int n)
        {
            Size = n;
            num = 0;
            array = new T[Size];//初始化数组
        }
        public void PutIn(T pet)//传入T类型参数
        {
            if (num < Size)
            {
                array[num++] = pet;
            }
            else
            {
                Console.WriteLine("Cage is full");
            }
        }
        public T TakeOut()//返回的参数类型是T类型
        {
            if (num > 0)
            {
                return array[--num];
            }
            else
            {
                Console.WriteLine("Cage is empty");
                return default(T);
            }
        }
    }
    public class program
    {
        public static void Main()
        {
            var dogCage = new Cage<Dog>(1);//这是什么形式?
            dogCage.PutIn(new Dog("A"));//new Dog("A")是作为T类类型,为Dog类创建实例
            dogCage.PutIn(new Dog("B"));
            var dog = dogCage.TakeOut();//var是什么类型?
            Console.ReadKey();
        }
    }

var关键字:

var 是3.5新出的一个定义变量的类型 其实也就是弱化类型的定义 VAR可代替任何类型 编译器会根据上下文来判断你到底是想用什么类型的 至于什么情况下用到VAR 我想就是你无法确定自己将用的是什么类型 就可以使用VAR 类似 OBJECT 但是效率比OBJECT高点。

或者通俗的讲:

  var可以理解为匿名类型,我们可以认为它是一个声明变量的占位符。它主要用于在声明变量时,无法确定数据类型时使用。

使用var定义变量时有以下四个特点:

1. 必须在定义时初始化。也就是必须是var s = “abcd”形式,而不能是如下形式: var s; s = “abcd”;

2. 一但初始化完成,就不能再给变量赋与初始化值类型不同的值了。

3. var要求是局部变量。

4. 使用var定义变量和object不同,它在效率上和使用强类型方式定义变量完全一样。

泛型方法:

方法的模型,泛型类中往往有泛型方法,普通类中也可以有泛型方法。

例子:

abstract public class Pet
    {
        public string _name;//重命名变量,也叫重构,一般下划线_表示私有
        public Pet(string name)
        {
            _name = name;
        }
        abstract public void Speak();

    }
    public class Dog : Pet
    {

        public Dog(string Name) : base(Name)
        {

        }
        override public void Speak()
        {
            Console.WriteLine(_name + "汪汪汪");
        }
        public void DogIsHappy<T>(T target)//<T>是传入参数的类型  (T target)是传入的参数。
        {
            Console.WriteLine("Happy:" + target.ToString());//  将T类型的target变成string类型然后输出
        }
    }
 class Person
    {

    }
    public class program
    {
        public static void Main()
        {
            Dog dog = new Dog("A");
            dog.DogIsHappy<Person>(new Person());
            dog.DogIsHappy<int>(3);
            Console.ReadKey();
        }
    }

运行结果:


约束:约束可以控制泛型参数的范围,缩小泛型范围。通常泛型参数可以是引用类型可以是值类型,可以是自定义可以是预定义。只有添加约束才可以调用泛型参数(如T)中的方法,负责只能调用object的方法。

约束类型:类名(该类或者继承该类的类),class,struct,接口名(该接口类型或者任何实现该接口的类型),new()(带有无参共有构造函数的类)

约束叠加规则:A.主约束(类名,class,struct) 只能有一个   B.接口约束可以有任意多个  C.构造约束

例子:

 void Cage<T>
            where T1:Pet, IClimbTree, New()
        {

        }

添加了有默认构造函数的new()约束,则可以在程序中new出一个T类型对象。添加Pet类约束,可以调用Pet类所有方法。添加接口约束,则可以调用接口中声明的方法。此时泛型类的参数类型只能在这些约束中选择。

泛型接口:



示例:

 abstract public class Pet
    {
        public string _name;//重命名变量,也叫重构,一般下划线_表示私有
        public int _age;
        public Pet(string name)
        {
            _name = name;
            _age = 0;
        }
        abstract public void Speak();
        public static Pet operator ++(Pet pet)//Pet是返回值类型
        {
            ++pet._age;
            return pet;
        }
        public void ShowAge()
        {
            Console.WriteLine(_name + _age + "岁");
        }
    }
    public class Dog : Pet
    {

        public Dog(string Name) : base(Name)
        {

        }
        override public void Speak()
        {
            Console.WriteLine(_name + "汪汪汪");
        }
    }
 public abstract class DogCmd
    {
        public abstract string GetCmd();
    }
    public class SitDogCmd :DogCmd
    {
        public override string GetCmd()
        {
            return "sit";
        }
    }
   public interface IDogLearn<C>where C :DogCmd//即这个接口可以调用DogCmd中的方法
    {
        void Act(C cmd);
    }
    public class Labra : Dog, IDogLearn<SitDogCmd>//传入SitDogCmd类型
    {
        public Labra(string name) : base(name)
        {

        }
        public void Act(SitDogCmd cmd)
        {
            Console.WriteLine(cmd.GetCmd());
        }
    }
    class program
    {
        public static void Main(string[] args)
        {
            Labra dog = new Labra("A");
            dog.Act(new SitDogCmd());
            Console.ReadKey();
        }
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值