十三、类的继承、访问级别

news2024/11/26 22:25:33

类的继承与访问控制

在这里插入图片描述

类的继承

  • 使用sealed修饰的类,是私有类,不能作为基类使用
  • C#中一个类,只能有一个父类,但是可以实现多个接口
  • 子类的访问级别不能超过父类的访问级别
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace HelloOOP {
    internal class Program {
        static void Main(string[] args) {
            //从代码上验证继承关系
            Type t = typeof(Car);
            Type tb = t.BaseType;
            Type ttTop = tb.BaseType;
            Console.WriteLine(ttTop.FullName);
            /* 所有的类都继承自Object
             * 并且Object上面就没有父类了,Object是处于最顶端的
             */
            Console.WriteLine(ttTop.BaseType == null);

            /* 是一个 is a, 一个子类的实例也是父类的实例
             * 一个学生一定是一个人
             * 一个父类的实例不一定是子类的实例
             * 一个人不一定是一个学生
             */
            Car car = new Car();
            Console.WriteLine(car is Vehicle);


        }
    }
    class Vehicle { }
    //Car类继承自Vehicle类
    class Car : Vehicle { }

    // 1.私有类,不能当做基类来使用
    sealed class Bycicle { }
}

成员的继承与访问

继承

继承的本质:派生类在基类已有的成员的基础之上,对基类进行的横向和纵向上的扩展

  • 当继承发生的时候,子类对父类所有的成员是全盘继承的,除了三种东西不会被继承

    • 静态构造器:用于初始化类的静态数据。
    • 实例构造器:在创建类的新实例时调用。 每个类都必须定义自己的构造函数。
    • 析构函数(终结器):由运行时的垃圾回收器调用,用于销毁类实例。
  • 在派生的过程当中,我们进行的是扩展

    也就是不能对父类的成员进行去除,只能扩展,这是静态类型语言(c++、c#、Java)的特点

    而某些动态语言(python、JavaScript)则可以去除父类的成员

  • 横向扩展即,类成员的增加;纵向扩展即,类成员的重写

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace HellloAccess {
    internal class Program {
        static void Main(string[] args) {
            Car car = new Car();
            Console.WriteLine(car.Owner);

        }
    }

    class Vehicle {
        public Vehicle()
        {
            this.Owner = "N/A";
        }
        public string Owner { get; set; }
    }
    class Car : Vehicle { 
        public Car() {
            //this.Owner = "Car Owner";
        }
        public void ShowOwner() {
            //只能访问上一级的对象
            Console.WriteLine(base.Owner);
            /* 创建子类对象的时候,是从基类的构造器开始
             * 一层一层往下构造的,最终构造出来子类的对象
             */
            Console.WriteLine(this.Owner);
            /* 当前这个base.Owner和this.Owner在这个例子中
             * 都指向的是同一个字符串即"Car Owner"
             * 因为子类中的构造器把原来的Owner覆盖了
             */
        }
    }
}

实例构造器无法被继承

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace HellloAccess {
    internal class Program {
        static void Main(string[] args) {
            Car car = new Car("Ygc");
            Console.WriteLine(car.Owner);
            /* 实例构造器无法被继承
             * 但是会先调用父类的实例构造器,然后再调用子类的实例构造器
             */
        }
    }

    class Vehicle {
        public Vehicle(string owner)
        {
            this.Owner = owner;
        }
        public string Owner { get; set; }
    }
    class Car : Vehicle {
        /* 当父类的构造器,是带参数的。
         * 那么父类的默认的构造器就会被覆盖掉
         * 那么此时调用子类的默认构造器是不行的
         * 因为调用子类的默认构造器,会先调用父类的默认构造器
         * 而此时,父类的默认构造器是不存在的,会发生冲突
         */

        //更改的办法:
        public Car() : base("N/A") {
            //this.Owner = "Car Owner";
        }
        //或者写一个带参数的构造器
        public Car(string owner) : base(owner)
        {
        }

        public void ShowOwner() {
            Console.WriteLine(this.Owner);
        }
    }
}

继承中的访问级别

派生类和派生记录不能具有高于其基类型的可访问性。

虽然基类的其他所有成员都可供派生类继承,但这些成员是否可见取决于它们的可访问性。 成员的可访问性决定了其是否在派生类中可见。

类成员的访问级别是以类的访问级别作为上限的。

internal class Student{
    public string name;
    //所以这个类成员是不能被其他程序集所访问的
}

父类中的私有字段被限制在了父类的类体中,子类是不能直接访问的,但是是继承了的

以下代码可以证明:


namespace MyLib
{
    public class Vehicle
    {
        private int _rpm;
        //命名前面加_表示,这是一个私有字段
        public void Accelerate() {
            _rpm += 1000;
        }
        //该属性返回的是私有字段/ 100之后的值
        public int Speed {  get { return _rpm / 100; } }

    }

    public class Car : Vehicle{  }
}


using System;
using MyLib;

namespace HellloAccess {
    internal class Program {
        static void Main(string[] args) {
            Car car = new Car();
            car.Accelerate();
            car.Accelerate();
            Console.WriteLine(car.Speed);
            /* 使用car对象调用父类的属性,能够成功返回
             * 说明,父类的私有字段实际上也是被子类所继承的,
             * 只是不能被car类所访问
             */
        }
    }
}

类成员的访问级别:

  • 只有在基类中嵌套的派生类中,私有成员才可见。 否则,此类成员在派生类中不可见。

    private会把访问级别限制在类的类体中,所以只有嵌套的派生类才能访问

    public class A
    {
        private int _value = 10;
    
        public class B : A
        {
            public int GetValue()
            {
                return _value;
            }
        }
    }
    
    public class C : A
    {
        //    public int GetValue()
        //    {
        //        return _value;
        //    }
    }
    
    public class AccessExample
    {
        public static void Main(string[] args)
        {
            var b = new A.B();
            Console.WriteLine(b.GetValue());
        }
    }
    // The example displays the following output:
    //       10
    
  • 受保护成员仅在派生类中可见。

    会把访问级别限制在继承链上,并且可以夸程序集

    protected更多的用在方法上

    namespace MyLib
    {
        public class Vehicle
        {
            protected int _rpm;
            private int _fuel;//表示油量
            //加油的方法
            public void Refuel() {
                _fuel = 100;
            }
            /* 烧油方法
             * 即不想暴露给外界,引发错误的调用
             * 又想继承给子类继续调用
             * 于是就用,protected访问修饰符
             */
            protected void Burn(int fuel) {
                _fuel -= fuel;
            }
            public void Accelerate() {
                Burn(1);//普通加速耗油1
                _rpm += 1000;
            }
    
            public int Speed {  get { return _rpm / 100; } }
    
        }
    
        public class Car : Vehicle{  
            public void TurboAccelerate() {
                //烧两次油,加速3000
                Burn(2);//涡轮增压加速,耗油2
                _rpm += 3000;
            }
        }
    }
    
    using System;
    using MyLib;
    
    namespace HellloAccess {
        internal class Program {
            static void Main(string[] args) {
                Car car = new Car();
                car.Refuel();//先加油
                car.TurboAccelerate();//再加速
                Console.WriteLine(car.Speed);
    
                Bus bus = new Bus();
                bus.Refuel();
                bus.SlowAccelerate();
                Console.WriteLine(bus.Speed);
                Console.ReadKey();
            }
        }
        class Bus: Vehicle {
            public void SlowAccelerate() {
                //夸程序集,仍然可以调用父类的protected的成员
                Burn(1);
                _rpm += 500;
            }
        }
    }
    
    
  • 内部成员仅在与基类同属一个程序集的派生类中可见, 在与基类属于不同程序集的派生类中不可见。

  • 公共成员在派生类中可见,并且属于派生类的公共接口。 可以调用继承的公共成员,就像它们是在派生类中定义一样。

    public class A
    {
        public void Method1()
        {
            // Method implementation.
        }
    }
    
    public class B : A
    { }
    
    public class Example
    {
        public static void Main()
        {
            B b = new ();
            b.Method1();
        }
    }
    

访问修饰符(全)

这一段是我抄的微软官方文档

  • public:同一程序集中的任何其他代码或引用该程序集的其他程序集都可以访问该类型或成员。 某一类型的公共成员的可访问性水平由该类型本身的可访问性级别控制。
  • private:只有同一 classstruct 中的代码可以访问该类型或成员。
  • protected:只有同一 class 或者从该 class 派生的 class 中的代码可以访问该类型或成员。
  • internal:同一程序集中的任何代码都可以访问该类型或成员,但其他程序集中的代码不可以。 换句话说,internal 类型或成员可以从属于同一编译的代码中访问。
  • protected internal:该类型或成员可由对其进行声明的程序集或另一程序集中的派生 class 中的任何代码访问。
  • private protected:该类型或成员可以通过从 class 派生的类型访问,这些类型在其包含程序集中进行声明。

在这里插入图片描述

各种东西的默认访问级别

默认情况下,类成员和结构成员(包括嵌套的类和结构)的访问级别为 private。 不能从包含该类型的外部访问私有嵌套类型。

在这里插入图片描述

面对对象的实现风格

面向对象语言学习方法的问题

不要因为学了某个语言,就极大的夸赞该语言的优点,而藐视其他语言的缺点。

C#中的派生和继承,仅仅只是众多语言派生和继承的一种风格,还有其他的派生和继承的风格。

**C#使用的是Class-based风格,基于类的封装、继承和多态。**目前是主流,C++,C#,Java。

JavaScript使用的是Prototype-based风格,基于原型的封装、继承和多态的方式

Java不是单根的类型系统,它的引用类型是单根的,但是它还有一套系统,叫基本类型系统。


有部分内容,我是抄的微软的官方文档。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1492872.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Mysql实战(1)之环境安装

1,进入:MySQL :: MySQL Downloads 2, 3, 4,

【Linux】磁盘情况、挂载,df -h无法看到的卷

文章目录 解决挂载、解决挂载完重启就消失1、查看linux下的硬盘挂载的空间、使用空间2、查看没有挂载的硬盘是否检测在系统中3、挂载 (挂载完,要在/etc/fstab 下面配置挂载信息 要不然重启挂载就消失了) 解决挂载、解决挂载完重启就消失 linu…

全局渐变滚动条样式

效果如下&#xff1a; APP.vue<style> /* 整个滚动条 */ ::-webkit-scrollbar {width: 5px;height: 10px; } /* 滚动条上的滚动滑块 */ ::-webkit-scrollbar-thumb {background-color: #49b1f5;/* 关键代码 */background-image: -webkit-linear-gradient(45deg,rgba(255,…

鸿蒙4.0-DevEco Studio界面工程

DevEco Studio界面工程 DevEco Studio 下载与第一个工程新建的第一个工程界面回到Project工程结构来看 DevEco Studio 下载与第一个工程 DevEco Studio 下载地址&#xff1a; https://developer.harmonyos.com/cn/develop/deveco-studio#download 学习课堂以及文档地址&#x…

1.1 深度学习和神经网络

首先要说的是&#xff1a;深度学习的内容&#xff0c;真的不难。你要坚持下去。 神经网络 这就是一个神经网络。里面的白色圆圈就是神经元。神经元是其中最小的单位。 神经网络 单层神经网络&#xff1a; 感知机 &#xff08;双层神经网络&#xff09; 全连接层&#xff1a; …

三色标记过程

可达性分析 GC过程中需要对对象图遍历做可达性分析。使用了三色标记法进行分析。 什么三色&#xff1f; 白色&#xff1a;尚未访问过。 黑色&#xff1a;本对象已访问过&#xff0c;而且本对象 引用到 的其他对象 也全部访问过了。 灰色&#xff1a;本对象已访问过&#xff0…

简单的排序算法

目录 1.直接插入排序 2.希尔排序 3.选择排序 4.冒泡排序 5.计数排序 6.排序总结 1.直接插入排序 &#xff08;1&#xff09;思想 所谓插入排序&#xff0c;就是将待排序数据插入到已经有序的数据中&#xff0c;为了使插入后数据依然有序&#xff0c;就要选中一个合理的…

易腐产品的多车厢电动车路径问题(2023)

Multi-Compartment Electric Vehicle Routing Problem for Perishable Products ABSTRACT 该研究首先提出了一个异质车队、多车室的易腐产品电动汽车路由问题&#xff08;MCEVRP-PP&#xff09;。我们捕捉到MCEVRP-PP的许多实际需求和限制&#xff0c;如多个温度区、硬时间窗…

Yolov8有效涨点,添加多种注意力机制,修改损失函数提高目标检测准确率

目录 简介 CBAM注意力机制原理及代码实现 原理 代码实现 GAM注意力机制 原理 代码实现 修改损失函数 YAML文件 完整代码 &#x1f680;&#x1f680;&#x1f680;订阅专栏&#xff0c;更新及时查看不迷路&#x1f680;&#x1f680;&#x1f680; http://t.csdnimg.c…

Claude 3 Sonnet 模型现已在亚马逊云科技的 Amazon Bedrock 正式可用!

今天&#xff0c;我们宣布一个激动人心的里程碑&#xff1a;Anthropic 的 Claude 3 Sonnet 模型现已在亚马逊云科技的 Amazon Bedrock 正式可用。 下一代 Claude (Claude 3) 的三个模型 Claude 3 Opus、Claude 3 Sonnet 和 Claude 3 Haiku 将陆续登陆 Amazon Bedrock。Amazon …

AIGC——Layer Diffusion使用潜在透明度的透明图像层扩散

前言 ControlNet的作者Lvmin Zhang大佬在新的一年又发布了新的工作LayerDiffusion&#xff0c;这个工作再次让人眼前一亮&#xff0c;和ControlNet一样&#xff0c;LayerDiffusion也是解决文生图中比较实际的问题&#xff0c;那就是生成透明的4通道RGBA图像&#xff0c;而且效…

在Mac上安装nginx+rtmp 本地服务器

需要使用终端命令&#xff0c;如果没有Homebrew&#xff0c;要安装Homebrew,执行&#xff1a; ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" 一、安装Nginx 1、先clone Nginx项目到本地&#xff1a; brew tap de…

目标检测5:采用yolov8, RK3568上推理实时视频流

上一个效果图&#xff0c;海康球机对着电脑屏幕拍&#xff0c;清晰度不好。 RK3568接取RTSP视频流&#xff0c;通过解码&#xff0c;推理&#xff0c;编码&#xff0c;最终并把结果推出RTSP视频流。 数据集采用coco的80个种类集&#xff0c;通过从yovo8.pt&#xff0c;转换成R…

在 Flutter 中使用 flutter_gen 简化图像资产管理

你是否厌倦了在 Flutter 项目中手动管理图像资产的繁琐任务&#xff1f; 告别手工输入资源路径的痛苦&#xff0c;欢迎使用“Flutter Gen”高效资源管理的时代。在本文中&#xff0c;我将带您从手动处理图像资源的挫折到动态生成它们的便利。 选择1&#xff1a;痛苦手动添加–…

网络编程(3/4)

广播 ​ #include<myhead.h>int main(int argc, const char *argv[]) {//1、创建套接字int sfd socket(AF_INET, SOCK_DGRAM, 0);if(sfd -1){perror("socket error");return -1;}//2、将套接字设置成允许广播int broadcast 1;if(setsockopt(sfd, SOL_SOC…

基于FastAPI构造一个AI模型部署应用

前言 fastapi是目前一个比较流行的python web框架&#xff0c;在大模型日益流行的今天&#xff0c;其云端部署和应用大多数都是基于fastapi框架。所以掌握和理解fastapi框架基本代码和用法尤显重要。 需要注意的是&#xff0c;fastapi主要是通过app对象提供了web服务端的实现代…

SINAMICS V90 PN 指导手册 第7章 回参考点功能

如果伺服是增量式编码器&#xff0c;共有三种回参考点模式&#xff0c;分别是 通过数字量输入信号REF设置回参考点通过外部参考挡块和编码器零脉冲回参考点仅通过编码器零脉冲回参考点 如果伺服是绝对值编码器&#xff0c;除了这三种以外&#xff0c;还可以通过“ABS”调整绝…

利用 Redis 和 Lua 实现高效的限流功能

简介 在现代系统中&#xff0c;限流是一种重要的机制&#xff0c;用于控制服务端的流量并保护系统免受恶意攻击或请求泛滥的影响。本文将介绍如何利用 Redis 和 Lua 结合实现高效的限流功能。 一、什么是限流 限流指的是对系统中的请求进行控制和调节&#xff0c;确保系统在…

Nginx 可视化管理软件 Nginx Proxy Manager

一、简介 Nginx Proxy Manager 是一款开源的 Nginx 可视化管理界面&#xff0c;基于 Nginx 具有漂亮干净的 Web UI 界面。他允许用户通过浏览器界面轻松地管理和监控 Nginx 服务器&#xff0c;可以获得受信任的 SSL 证书&#xff0c;并通过单独的配置、自定义和入侵保护来管理…

ARM单片机中程序在ROM空间和RAM空间的分布(分散加载文件,Scatter-Loading Description File)

对于 K e i l u V i s i o n I D E Keil\quad uVision\quad IDE KeiluVisionIDE&#xff0c;程序编译好之后&#xff0c;代码的下载位置&#xff08; R O M ROM ROM空间&#xff09;以及代码运行的时候使用的 R A M RAM RAM空间&#xff08; R A M RAM RAM空间&#xff09;默认…