C#面向对象(方法参数)

一、面向对象

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

(对象声明的三种方式:以普通基类身份声明的变量并用基类对象赋值,以普通基类身份声明的变量并用子类对象赋值,以子类身份声明的变量并用子类对象赋值,抽象类声明的变量必须由子类进行赋值(抽象类不能new))

  1. 类的分类:普通基类,抽象基类(abstract):抽象类天生(public)是给人继承的,不能new(声明对象),纯抽象类(接口)

  2. 基本概念:

  • 类的统一成员分类:私有成员(仅在类的内部使用),共有成员(全宇宙可见),受保护成员(在类的内部和子类中使用)
  • 子类继承基类:子类可以继承基类的共有成员和受保护成员,不能继承私有成员
  • 子类访问基类成员时一般要使用base关键字
  • 类成员的扫描顺序:以谁身份声明的变量就在谁身上开始扫描,先近后远
  • 类的访问原则:类的外部只能访问类的共有成员,子类可访问基类的共有成员和受保护成员(继承)
  • 构造函数:函数名和类名相同(函数没有返回类型,使用public修饰)

构造函数:函数名和类名相同(函数没有返回类型,使用public修饰)
4、类的成员分类:

  • 普通基类虚成员:类成员使用virtual 关键字修饰的为类的虚成员,可以被子类重写,被子类重新的条件条件是子类的同名方法必须由override关键字修饰(使用情景:以基类身份声明的变量,并以子类对象赋值,当调用方法时现在基类身上开始扫描,找到需要使用的方法并且方法是用virtual关键字修饰的虚成员,转而向子类进行扫描,如果在子类身上找到对应的方法,并且该方法用override关键字进行修饰,那么就调用子类方法,否则调用基类自己的方法)
  • 抽象类成员:实例成员(在子类身上得到体现),抽象成员:抽象类中的抽象成员没有具体的实现,也就是没有方法体,就是没有花括号。所以继承抽象基类的子类必须实现基类的抽象成员,才能使抽基类的抽象成员得到体现

5、抽象类特别注意事项:继承抽象类的子类必须实现抽象类的抽象成员,就是必须使用override(重写)关键子修饰基类同名抽象成员

6、对继承概念的认识:子类继承了基类,在程序入口调用方法时,子类的构造函数继承了基类的构造函数。以子类身份声明的变量并以子类对象赋值,当调用子类中成员时,按照类的访问规则,此时我们可以发现,基类通过子类继承的构造函数,获得了具体的成员)


 abstract  class Document
    {

        public string path { get; set; }
        public abstract void Init();

        public abstract void SetParament();

        public abstract void Print();
    }

接口

  1. interface声明接口,接口是纯抽象类,不能new。接口定义一些成员,不是用public关键字修饰,默认就是共有的接口成员是纯虚成员
  2. 主程序中调用接口时注意:
  • 以接口身份声明的变量必须以实现接口的类的对象进行赋值
  • 以那个接口身份声明的变量只能点出这个接口定义的成员(当一个类型继承了多个接口时,使用这个类型调用接口时)
  • 接口成员是方法的声明
  1. 接口的实现:实现接口的类必须实现接口成员
  • 接口的显示实现和隐式实现:当类实现单接口时一般使用隐式实现,实现多接口特别是多接口中定义了同名成员时要使用显示实现(加接口名前缀)£子类访问基类:在子类的内部可以访问基类共有成员和受保护成员,在子类的外部。子类对象只能访问基类的共有成员(类的外部只能访问类的共有成员)
//接口是纯抽像类,不能有任何实例成员,接口的成员是方法的声明
    public interface IWeapon
    {
        //接口成员天生就是public所以你不能加public关键字
        void Fire();
    }
    //实现接口的类必须实现接口成员
    public class Gun : IWeapon
    {
        public void Fire()
        {
            Console.WriteLine("pa peng pa peng");
        }
    }

    public class Sword : IWeapon
    {
        public void Fire()
        {
            Console.WriteLine("七剑下天山");
        }

    }

继承

  1. 子类继承基类,基类的构造函数:声明子类对象时,子类的构造函数要先给基类构造函数传参,基类构造函数先于子类构造函数执行

函数的重载

一个类中,函数名相同签名不同的方法称为函数的重载,签名指:返回类型,参数类型,参数数量,参数的顺序

区别普通基类虚成员和抽象基类抽象成员

普通基类虚成员使用virtual关键字修饰,其子类可以不必重写(override)其虚成员
抽象基类抽象成员使用abstract关键字修饰,其抽象成员没有具体的实现必须由子类来实现(override)

抽象基类多态的理解

子类继承抽象基类使用基类作为一个大的主题,使用引擎类对基类的访问,实现对每个继承基类子类成员的调用(联想动物代码)

接口(纯抽象类)和抽象类的异同

异:接口是纯抽象类,不能有任何实例成员,抽象类可以存在实例成员,并在子类中可以得到体现。接口使用关键字interface修饰,抽象类使用abstract修饰,接口的成员不使用任何的修饰字,抽象类抽象成员使用abstract进行修饰,子类继承抽象基类必须重写基类中的抽象成员(override)
同:接口的成员(方法),抽象类的抽象成员不能具体的实现,也就是没有方法体,也就是没有花括号,只需要声明

接口实现多态(多变性、灵活性)

语法级别优化代码

  • 文档抽象类
abstract  class Document
    {

        public string path { get; set; }
        public abstract void Init();

        public abstract void SetParament();

        public abstract void Print();
    }
  • 图片类
class Bmpl:Document
    {

        public Bmpl()
        {

        }

        public Bmpl(string path)
        {
            base.path = path;
        }

        public override void Init()
        {
            Console.WriteLine("Bmpl初始化中。。。。");
        }

        public override void SetParament()
        {
            Console.WriteLine("Bmpl设置参数中。。。。");
        }

        public override void Print()
        {
            Console.WriteLine("Bmpl打印中。。。。");
        }
    }
  • PDF类
class Pdf:Document
    {

        public string path { set; get; }

        public Pdf()
        {

        }

        public Pdf(string path)
        {
            this.path = path;
        }

        public override void Init()
        {
            Console.WriteLine("Pdf初始化中。。。。");
        }

        public override void SetParament()
        {
            Console.WriteLine("Pdf设置参数中。。。。");
        }

        public override void Print()
        {
            Console.WriteLine("Pdf打印中。。。。");
        }
    }
  • 工厂类
class DocumentFactory
    {
        /// <summary>
        /// 工厂方法,失败返回null
        /// </summary>
        /// <param name="path">路径</param>
        /// <returns>失败返回null</returns>
        public static Document GetDocumentPath(string path)
        {
            string exection = "pdf";

            if (exection.ToLower().Equals("pdf"))
            {
                return new Pdf(path);
            }else if (exection.ToLower().Equals("bmpl"))
            {
                return new Bmpl(path);
            }

            return null;
        }
    }
//测试调用
string path = "pdf";

Document document = DocumentFactory.GetDocumentPath(path);
if (document == null)
{
    Console.WriteLine("暂不支持打印该类型文件!。。。。");
    return ;
}
print(document);

二、方法和参数

  1. ref参数传递
    使用ref传递参数可以和所复制的参数达到同等
 //加法运算
        public int add(ref int x,ref int y)
        {
            return x + y;
        }
	public void AddByRef(ref int a, int b, int c)
	    {
       		 a = a + b + c; // 可以直接使用a 
     	 }
	//调用
		int x = 5;
        int y = 6;
        var demo01 = new Demo02();
        int a=  demo01.add(ref x,ref y);
        Console.WriteLine(a);

	//refSum 必须赋值
         int refSum = 1;
         int rv1 = 2;
         int rv2 = 3;
    //如果refSum没有赋值,这里会报错:使用了未赋值的局部变量 refSum
         AddByRef(ref refSum, rv1, rv2);
        Console.WriteLine("refSum : " + refSum + "  v1: " + rv1 + "   v2: " + rv2);

注意:方法有ref使用调用方法是也要使用ref关键字修饰,因此,,通过引用传递值类型时没有值类型装箱。若要使用 ref 参数,则方法定义和调用方法都必须显式使用 ref 关键字

  1. 使用out
 public void AddByOut(out int a, int b, int c)
    {
 //a = a + b + c;// a 未被赋值,不能直接使用,即使是调用的地方 out对应的参数初始化也没用
        a = b + c;
    }

//outSum没必要赋值,赋值了也完全没用。
//如果AddByOut函数内部直接使用out对应的参数,会报错:使用了未被赋值的 out 参数a
		int outSum = 1;
		int ov1 = 2;
		int ov2 = 3;
		AddByOut(out outSum, ov1, ov2);
		Console.WriteLine("outSum : " + outSum + "  v1: " + ov1 + "   v2: " + ov2);

通常一个方法只能返回一个值,但是如果在某些时候,我们想要返回多个值,例如某个方法将一个浮点数分割成一个整数和一个小数返回去。这个时候我们就要用到out关键字

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值