C#学习第二弹

今天来学习面向对象程序设计方法。

面向对象要先理解两个部分,第一个部分是类;第二个部分是对象。

一.类 ( 具体到抽象的过程 )

    类可以理解为一类,这一类事物具有这某种共性。比如“人”。对一个人来讲,我们可以了解他的“姓名”、“年龄”、“身高”、“体重”......等等一系列你能想到的,对应 “人” 这个类的属性。普遍来讲,这些属性加在哪一个人的身上都适用。

    类的声明很简单 使用 class 关键字 加上 类名 就可以了

举例代码

public class People
    {
        public People()
        {
        }
    }

      1.public 表示访问权限 是 public 公有

      2.class People { } 是一个类的声明 在 { } 中的则是这个类包含的方法

      3.public People ( ) { } 是这个类的构造函数(系统自动声明) 小括号 ( ) 里面是需要传递的参数,{ }里面是这个方法的具体实现。

      4.访问修饰符常用的有两个

         「1」public 公有 没有访问限制

         「2」private 私有 只有类内部成员有权访问

public class People
    {
        private string name;
        private int age;

        public People(string nameStr, int ageInt)
        {
            this.name = nameStr;
            this.age = ageInt;
        }

        public int Age
        {
            get
            {
                return age;
            }
            set
            {
                age = value;
            }
        }
    }
public static void Main(string[] args)
        {
            People memberA = new People("张三", 18);

            Console.WriteLine("get 获取年龄" + memberA.Age);
            memberA.Age = 23;
            Console.WriteLine("set 修改后,get 获取年龄" + memberA.Age);
        }

在这之中,你如果想 通过 memberA.age 来获取年龄是不可能的,因为age的访问修饰符是private。

红色区域应当注意。

二.对象 ( 抽象到具体 ) 

关键字 new

在上面的代码 Main()方法里,就实例化出了一个对象 memberA 而调用的方法是类中 构造函数的方法。


三.封装

对于封装,举一个例子。就好比你开车。你开车的时候,只需要控制方向盘,油门,刹车,就好了。你并不需要了解为什么向左打方向盘车子内部是怎么运作到轮子上,然后车向左转的。你只要明白转方向盘,车会跟着向那个方向转就好啦。

对于一个或者多个项目也是这样,程序员并不需要让人人都懂程序,只是把外部的接口交给用户(方向盘), 用户会打方向盘就好啦。这样的好处有很多。

    1.能够对类内的成员访问进行合理的控制,使得不同类之间的影响达到最低。

    2.对于封装好的模块,只要知道外部接口,以及规则就可以直接调用,省去很多些重复代码的时间,加快开发周期,提高开发效率。

注: 之所以要声明类,就是为了便于以后调用,不论是继承,还是多态,都大大提高了开发效率。


四.继承

继承就好比,师傅与徒弟的关系。师傅把自己的绝学交给了徒弟,至于徒弟怎么发挥,师傅就没有办法干涉了。同时在C#中一个徒弟只能有一个师傅。

举例代码

    public class People
    {
        protected string name;
        protected int age;

        public People(string nameStr, int ageInt)
        {
            this.name = nameStr;
            this.age = ageInt;
        }
    }

    public class Man : People
    {
        
        public Man (string nameStr, int ageInt) : base(nameStr, ageInt)
        {
            this.name = nameStr;
            this.age = ageInt;
        }

        public void Display()
        {
            Console.WriteLine("在子类man中的name是:" + this.name);
            Console.WriteLine("在子类man中的age是:" + this.age);

            Console.WriteLine("在基类people中的name是:" + base.name);
            Console.WriteLine("在基类people中的age是:" + base.age);

        }
    }
        public static void Main(string[] args)
        {
            Man memberA = new Man("张三", 18);

            memberA.Display();

        }

在上面的例子中,姓名和年龄的访问修饰符已经被我改成了protected 这是为了保证people的子类man也可以访问到这两个变量。同时在例子中标记为红色的两行代码,其实没有什么实质性的作用,删除并不影响代码的运行。同时派生类man当中的name,age两个变量的内容是存储在people类中的name,和age里面的。

在这里要注意一点

    public class People
    {
        protected string name;

        //父类无参数
        public People()
        {
            Console.WriteLine("No parameter in People");
            name = "No name input!!";
        }

        //父类有参数
        public People(string name)
        {
            this.name = name;
        }

    }

    public class Man : People
    {
        //子类无参数
        public Man()
        {
            Console.WriteLine("No parameter in man");
        }

        //子类有参数
        public Man(string name) //: base(name)
        {
            this.name = name;
        }

        public void Display()
        {
            Console.WriteLine("Name : " + name);
        }   
在这个例子中,对于People 以及Man我分别声明了两种构造函数,一种是无参数,一种是有参数。但是对与子类我并没有声明说子类去继承哪个构造函数。我们来看一下结果
        public static void Main(string[] args)
        {
            Man memberA = new Man("张三");
            memberA.Display();

            Console.WriteLine("\n************华丽的分割线****************\n");

            Man memberB = new Man();
            memberB.Display();

        }

结果

No parameter in People
Name : 张三

************华丽的分割线****************

No parameter in People
No parameter in man
Name : No name input!!

对于 memberB 来讲因为参数,所以先调用父类当中没有参数的父类构造函数,然后再调用子类当中的构造函数。

对于 memberA 来讲虽然传递了一个姓名的参数,但是派生类man还是调用父类中的无参数构造函数,也就是说如果不指定继承构造函数,子类都会默认调用父类当中的无参构造函数。

把子类有参数那里的 base 前的注释解开

        //子类有参数
        public man(string name) : base(name)
        {
            this.name = name;
        }

再运行一次,结果如下

Name : 张三

************华丽的分割线****************

No parameter in People
No parameter in man
Name : No name input!!
可见指定之后,派生类当中的构造函数就不会再去调用默认的无参数类型的构造函数了。


五.多态

在上面继承的例子中,People 的构造方法分别定义了两个,这就是一种多态的体现。

    1.方法的多态:函数名相同,但是参数类型或是参数个数不同,这叫做函数重载。这方面不过多介绍,但是要注意当两个方法的方法名、参数类型、参数数量都相同的时候,只有返回值类型不同是不可以的。

    2.类的多态:类的多态就好比,一个师傅下面有n多个徒弟,徒弟与徒弟之间平起平坐,不分大小。

举例代码

    public class People
    {
        protected string name;
        protected int age;

        public People(string name, int age)
        {
            this.name = name;
            this.age = age;
        }

        public virtual void Display()
        {
            Console.WriteLine("The name is: " + name);
            Console.WriteLine("The age is: " + age + "\n");
        }

    }

    public class Male : People
    {
        public Male(string name, int age) : base(name, age)
        {}

        //public override void Display()
        //{
        //    Console.WriteLine("This man's name is : "  + name);
        //    Console.WriteLine("He's {0} years old \n" , age);
        //}

	}

    public class Female : People
    {
        public Female(string name, int age) : base(name, age)
        {}

		//public override void Display()
        //{
        //    Console.WriteLine("This woman's name is : " + name);
        //    Console.WriteLine("She is {0} years old \n" , age);
        //}

	}

        public static void Main(string[] args)
        {
            People memberA = new People("张三" , 20);
            People memberB = new Male("李四" , 21);
            People memberC = new Female("王五" , 23);

            memberA.Display();
            memberB.Display();
            memberC.Display();
        }

结果如下

The name is: 张三
The age is: 20

The name is: 李四
The age is: 21

The name is: 王五
The age is: 23

红色部分是需要重点关注和理解的地方。

划掉注释,运行结果如下

The name is: 张三
The age is: 20

This man's name is : 李四
He's 21 years old 

This woman's name is : 王五
She is 23 years old 

在上面声明的三个变量都是People类,然而用new 进行实现的时候就出现了不同。

同样一个方法,在People里面进行了 虚方法( virtual )声明,以及实现。在他的派生类里面进行了重写  override 。当子类没有该方法的时候,实例化出来的对象就不会在new出的派生类当中。

注:「1」如果People类里面没有Display()这个方法,实例化出来的对象是不能够调用的,不论子类是否进行了声明。

      「2」因为声明的People类 所以它的派生类(Male Female)里面独有的方法 那个声明对象是不能调用的。


    3.关键字 

        「1」is is关键字用来判断某个对象是否属于某个类,返回类型为bool变量 ,在上面代码的基础上在添加这么几行

            bool BIsPeople = memberB is People;
            bool BIsMale = memberB is Male;
            bool BIsFemale = memberB is Female;
            Console.WriteLine("memberB is People? The answer is " + BIsPeople);
            Console.WriteLine("memberB is Male? The answer is " + BIsMale);
            Console.WriteLine("memberB is Female? The answer is " + BIsFemale);

结果如下

memberB is People? The answer is True
memberB is Male? The answer is True
memberB is Female? The answer is False

通过结果我们可以观察到 memberB 即使 People 类,又是 Male 类。

       「2」as as关键字用于类与类之间的类型转换,当然如果类与类之间不能转换的时候,会返回null

    public class Male : People
    {
        public Male(string name, int age) : base(name, age)
        {}

        public override void Display()
        {
            Console.WriteLine("This man's name is : "  + name);
            Console.WriteLine("He's {0} years old \n" , age);
        }

        public void MaleText()
        {
            Console.WriteLine("This method is male's.");
        }
    }
        public static void Main(string[] args)
        {
            People memberA = new Male("张三" , 18);
            Male memeberB = new Male("李四" , 20);

            //memberA.MaleText();
            //memeberB.MaleText();

            People memberA_01 = memberA as People;
            People memberB_01 = memeberB as People;
            Female memberB_02 = memberB_01 as Female;

            Console.WriteLine(memberA_01 != null);
            Console.WriteLine(memberB_01 != null);
            Console.WriteLine(memberB_02 != null);

           
        }

结果如下

True
True
False

可见,只要是用 is 关键字判断为true的,就可以用 as 进行类型转换。

as 进行类型转换的时候,不会因为转换不了系统崩掉,而是会返回一个null.只要合理利用,就可以减少代码开发出现bug的程度,同时缩短运行时间。

这方面理解的还不是很透彻,欢迎大家在评论区进行讨论。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
目标检测(Object Detection)是计算机视觉领域的一个核心问题,其主要任务是找出图像中所有感兴趣的目标(物体),并确定它们的类别和位置。以下是对目标检测的详细阐述: 一、基本概念 目标检测的任务是解决“在哪里?是什么?”的问题,即定位出图像中目标的位置并识别出目标的类别。由于各类物体具有不同的外观、形状和姿态,加上成像时光照、遮挡等因素的干扰,目标检测一直是计算机视觉领域最具挑战性的任务之一。 二、核心问题 目标检测涉及以下几个核心问题: 分类问题:判断图像中的目标属于哪个类别。 定位问题:确定目标在图像中的具体位置。 大小问题:目标可能具有不同的大小。 形状问题:目标可能具有不同的形状。 三、算法分类 基于深度学习的目标检测算法主要分为两大类: Two-stage算法:先进行区域生成(Region Proposal),生成有可能包含待检物体的预选框(Region Proposal),再通过卷积神经网络进行样本分类。常见的Two-stage算法包括R-CNN、Fast R-CNN、Faster R-CNN等。 One-stage算法:不用生成区域提议,直接在网络中提取特征来预测物体分类和位置。常见的One-stage算法包括YOLO系列(YOLOv1、YOLOv2、YOLOv3、YOLOv4、YOLOv5等)、SSD和RetinaNet等。 四、算法原理 以YOLO系列为例,YOLO将目标检测视为回归问题,将输入图像一次性划分为多个区域,直接在输出层预测边界框和类别概率。YOLO采用卷积网络来提取特征,使用全连接层来得到预测值。其网络结构通常包含多个卷积层和全连接层,通过卷积层提取图像特征,通过全连接层输出预测结果。 五、应用领域 目标检测技术已经广泛应用于各个领域,为人们的生活带来了极大的便利。以下是一些主要的应用领域: 安全监控:在商场、银行
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值