04_C#学习_面向对象

2019-03-07

面向对象编程

特点:封装,继承,多态(子类)
优点:易维护,易扩展,易开发
—— 与面向过程编程相对。

1. 继承

为什么要继承:不用写重复的代码
怎么实现继承:一个类派生于另一个基类,它拥有该基础类型的所有成员字段和函数。
理解:直接将基类里面的代码copy到派生类中
规则:单继承,只能继承一个父类。

04_C#学习_面向对象_第1张图片

语法:

class ChildClass : ParentClass
{...
}

2. 隐藏方法

派生类希望在从基类继承来的方法中,进行独特性的改变。

  • 不能删除基类中任何方法,但可以使用相同名称的方法来屏蔽基类方法。
  • 语法细节:在派生类中声明相同名称和类型的成员;并在前面添加new关键词
04_C#学习_面向对象_第2张图片
class Pet
    {
        public string Name;
        public void PrintName()
        {
            Console.WriteLine("Pet's name is:" + Name);
        }
    }
 class Dog:Pet
    {//new 方法;在派生类中进行了方法修改
        new public void PrintName()
        {
            Console.WriteLine("狗的名字是:" + Name);
        }
    }
//在Dog类实例化对象下,执行new方法
//在Pet类实例化对象,执行基类原来的方法

3. 虚方法和多态:virtual,override

  1. 设计原则:尽量依赖抽象类(Pet),而不依赖于具体类(Dog)

  2. 基类的引用:基类的引用,并指向派生类

Pet dog = new Dog();

dog能访问的内容是:Pet基类中正常部分+Pet基类中的虚方法在Dog派生类中override的重写对象。

  1. 提高效率:首先,我们希望能进行统一的管理,通过一个容器(数组)能保存所有对象(Dog,Cat),但是这些对象必须是同类型的。 所以,通过一个基类类型的数组储存所有对象,并通过虚方法和多态实现个性化。
Pet[] pets = new Pet[] { new Dog("Jack"), new Cat("Tom") };
  1. 虚方法和多态
    虚方法:声明为virtual的方法是虚方法。基类的虚方法可以在派生类中使用override进行重写
    多态:指向派生类的基类引用,调用虚函数时候,会调用派生类中的同名重写函数,便是多态。
//基类Pet
  class Pet{
        public string Name;
        public void PrintName()
        {
            Console.WriteLine("Pet's name is:" + Name);
        }
        virtual public void Speak()
        {
            Console.WriteLine(Name+" is speaking");
        }
    }
//子类Dog
 class Dog:Pet{
        public Dog(string name)
        {
            this.Name = name;
        }

        public override void Speak()
        {
            Console.WriteLine(Name + " is speaking:"+"wangwang");
        }
    }
//子类Cat
 class Cat:Pet {
        public Cat(string name)
        {
            Name = name;
        }
        public override void Speak()
        {
            Console.WriteLine(Name + " is speaking:"+"miaomiao");
        }
    }
//主程序
    class Program{
        static void Main(string[] args){
            Pet[] pets = new Pet[] { new Dog("Jack"), new Cat("Tom") };
            for (int i = 0; i < pets.Length; i++)
            {
                pets[i].PrintName();
                pets[i].Speak();
            }
        }
    }

4. 派生类及构造函数

  1. 调用顺序


    04_C#学习_面向对象_第3张图片
  2. 指向派生类的基类引用,要用派生类的构造函数,派生类的构造函数通过public Dog(string name):base(name)引用调用基类的构造函数。

   class Pet{
        public Pet(string name)
        {
            _name = name;
        }
}
   class Dog:Pet{
        public Dog(string name):base(name)
        {
        }
}
  class Cat:Pet{
        public Cat(string name):base(name)
        {
        }
}

 Pet[] pets = new Pet[] { new Dog("Jack"), new Cat("Tom") };

5. 抽象方法和类 abstract

  • abstract比virtual更加抽象,无函数体,必须要在子类进行重写

  • 有抽象方法的一定是抽象类,需要声明为abstract class Pet

  • 抽象类的目的:被继承。

  • 抽象类不能实例化,用abstract修饰

  • 抽象类可以包含抽象成员和普通成员,抽象对象在派生类中需要用override重写

abstract class Pet
    {
        public Pet(string name)
        {
            _name = name;
        }
        abstract public void Speak();
 }

6. 密闭类和密闭方法

  • 关键词:sealed
  • 为什么要密闭:不希望原来的类或者方法被其他人修改或重写(比如:string类是sealed类)
  • 密闭方法:如果一个基类方法不希望子类对其重写,就可以不声明virual。如果是派生类方法不希望被子类重写,同时又是override重写,就可以使用sealed机制
sealed public override void Speak()

7. 接口

接口笔记链接

  • 接口是什么:接口是指一组函数成员,而不实现他们的引用类型。(比抽象类还抽象,像没有普通函数的抽象类)
interface ICatchMice
{
  void CatchMice(); //里面是空方法
}
-- 不能加任何访问修饰符,但默认是public
  • 作用:用来被别的类实现,被继承
//定义接口
interface ICatchMice
    {
        void CatchMice();
    }
interface IClimbTree
    {
        void ClimbTree();
    }
//Cat类继承接口
class Cat:Pet,ICatchMice,IClimbTree
    {
        public Cat(string name):base(name)
        {
        }
        public void CatchMice()
        {
            Console.WriteLine("Catch Mice");
        }
        public void ClimbTree()
        {
            Console.WriteLine("Climb Tree");
        }
    }
 class Program
    {
        static void Main(string[] args)
        {
            Cat cat = new Cat("Tom2");
            cat.CatchMice(); //用对象调用方法
            IClimbTree climb = (IClimbTree)cat;
            climb.ClimbTree(); //用接口调用方法
            ICatchMice catchMice = (ICatchMice)cat;
            catchMice.CatchMice();
        }
    }

8. 结构与类

  1. 不同点
  • 结构是值类型(在栈中),类是引用类型(在堆中)
  • 结构不支持继承但可以实现接口,类支持继承
  • 结构不能定义默认构造函数,编译器会定义
  1. 适用类型
  • 结构:由于分配内存块,作用域结束即被删除,不需要垃圾回收,用于小型结构类型。但传递过程中会复制,应该适用ref引用提高效率

  • 类:用于需要继承体系的场合

9. 静态成员

  • 什么是静态成员:标识为stactic的字段,方法,属性,构造函数,时间,就是静态成员。static int Num

  • 重点:静态成员被类的所有实例共享,所有实例都访问统一内存位置

  • 如何访问静态成员:直接通过类名访问 Dog.Num+=1;

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

  • 静态构造函数:静态构造函数用于初始化静态字段;在引用静态成员之前和创建任何实例之前调用;与类同名,使用static,无参数,无访问修饰符 static Dog()

 class Dog:Pet
    {
        static int Num;
        static Dog()  //静态构造函数初始化Num,仅能访问静态成员
        {
            Num = 0;
        }
        public Dog(string name):base(name)
        {
            ++Num;
        }
        static public void ShowNum()
        {
            Console.WriteLine("Dog's number is " + Num);
        }
    }
 class Program
    {
        static void Main(string[] args)
        {
           Dog dog = new Dog("Tim");
           Dog.ShowNum();  //通过类直接调用静态方法
         }
     }

10. 静态类

  • 静态类:只包含静态的方法和属性,并标识为static。

  • 静态类不能创建实例,不能被继承。可以为静态类定义一个静态构造函数。

  • 作用:主要用于基础类库(如数学库)和扩展方法。

  • 扩展方法:如有源代码,直接添加一个新方法;如果不能修改但也不是密闭类,可以派生子类扩展;如果以上条件都不满足,可使用静态类扩展方法

  • 扩展方法的第一个参数类型,必须是this+类名。之后在实例对象中可以像自己的方法一样能直接调用静态类的方法

static class PetGuide
    {
        public static void HowToFeedDog(this Dog dog)
        {
            ...  
            Console.WriteLine("Play a vedio about how to feed a dog");
        }
    }
class Program
    {
        static void Main(string[] args)
        {
            Dog dog = new Dog("Tim");
            dog.HowToFeedDog();  //像自己的方法一样直接调用静态类的方法
         }
    }

11. 装箱和拆箱

  • 装箱:值类型转换为引用类型,是一种隐式转换
  • 为什么要装箱:进行统一的操作和统一的存储
int i = 3;
object oi = null;
oi = i;
04_C#学习_面向对象_第4张图片
  • 拆箱:是将装箱后的对象转换为值类型的过程,是一种显示转换。
int i = 3;
object oi = i;
int j = (int) oi;

12. 自定义转换

  • 什么是自定义转换:为自己的结构或者类定义显示和隐式转换
  • 为什么:为了让结构或者类可以变成一个预期相关的类型,并且这种转换更简单
  • 隐式转换语法:
 static public implicit operator Cat(Dog dog)
        {
            return new Cat(dog._name);
        }
  • 显式转换语法:
static public explicit operator Dog(Cat cat)
        {
            return new Dog(cat._name);
        }
  • 应用:
   Dog dog = new Dog("Jack");
    dog.Speak();
    Cat cat = dog;
    cat.Speak();
    Dog dog2 = (Dog)cat;
    dog2.Speak();

13. 重载运算符

  • 含义:利用现有的某种运算符,针对自定义类或结构,定义某种运算操作(公狗+母狗=新生狗狗)

  • 意义:利用现有运算符,简化操作,具有一定相关性

  • 运算符:


    04_C#学习_面向对象_第5张图片
  • 不能创造新运算符,不能改变运算符语法,不能重定义运算符处理预定义类型,不能改变运算符的优先级和结合性。

  • 语法:public static Dog operator +(Dog male,Dog female)

class Dog:Pet
    {...
 static public Dog operator +(Dog dog1,Dog dog2)
        {
            if ((dog1.Sex == (Sex)0 && dog2.Sex == (Sex)1) || (dog1.Sex == (Sex)1 &&dog2.Sex == (Sex)0) )
            {
                return new Dog(dog1._name + dog2._name, Sex.female);
            }
            else
            {
                Console.WriteLine("Can't bath new baby");
                return null;
            }
        }
    }

            Dog dog1 = new Dog("Jack", Sex.male);
            Dog dog2 = new Dog("Mary", Sex.female);
            Dog littedog = dog1 + dog2;  //运算符重载
            littedog.ShowSex();

你可能感兴趣的:(04_C#学习_面向对象)