12.22 C#基础

一、虚函数

1.定义

虚函数,是指被virtual关键字修饰的成员函数。

在某基类中声明为virtual并在一个或多个派生类中被重新定义的成员函数,用法格式为:virtual 函数返回类型 函数名(参数列表){函数体};实现多态性,通过指向派生类的基类指针或引用,访问派生类中同名覆盖成员函数。

2.实现原理

每个虚函数都会有一个与之对应的虚函数表,该虚函数表的实质是一个指针数组,存放的是每一个对象的虚函数入口地址。对于一个派生类来说,他会继承基类的虚函数表同时增加自己的虚函数入口地址,如果派生类重写了基类的虚函数的话,那么继承过来的虚函数入口地址将被派生类的重写虚函数入口地址代替。在程序运行时会发生动态绑定,将父类指针绑定到实例化的对象实现多态。

二、指针和引用的区别(......C#里引用是什么?

1.引用:

  • 不能为空,不存在对空对象的引用,
  • 必须初始化,初始化后不能改变指向,
  • 直接访问对象,引用的大小是所引用对象的大小,没有const,不需要分配内存空间

2.指针:

  • 可以为空,可以指向空对象,
  • 不用初始化,可以改变所指对象的值,
  • 间接访问对象,指针的大小是指针本身大小(通常4字节),有const,需要分配内存空间

自增运算符意义不同。

引用比指针使用起来形式上更漂亮,使用引用指向的内容时可以之间用引用变量名,而不像指针一样要使用*;定义引用的时候也不用像指针一样使用&取址。引用比指针更安全。由于不存在空引用,并且引用一旦被初始化为指向一个对象,它就不能被改变为另一个对象的引用,因此引用很安全。对于指针来说,它可以随时指向别的对象,并且可以不被初始化,或为NULL,所以不安全。const指针虽然不能改变指向,但仍然存在空指针,并且有可能产生野指针(即多个指针指向一块内存,free掉一个指针之后,别的指针就成了野指针)。

指针指向一块内存,它的内容是所指内存的地址;而引用则是某块内存的别名,引用不改变指向。

三、C#中有哪些常用的容器类,各有什么特点

List,HashTable,Dictionary,Stack,Queue

  • Stack栈:先进后出,入栈和出栈,底层泛型数组实现,入栈动态扩容2倍
  • Queue队列:先进先出,入队和出队,底层泛型数组实现,表头表尾指针,判空还是满通过size比较。
    Queue和Stack主要是用来存储临时信息的
  • Array数组:需要声明长度,不安全
  • ArrayList数组列表:动态增加数组,不安全,实现了IList接口(表示可按照索引进行访问的非泛型集合对象),Object数组实现
  • List列表:底层实现是泛型数组,特性,动态扩容,泛型安全。
    将泛型数据(对值类型来说就是数据本身,对引用类型来说就是引用)存储在一个泛型数组中,添加元素时若超过当前泛型数组容量,则以2倍扩容,进而实现List大小动态可变。(注:大小指容量,不是Count)
  • LinkList链表
    1、数组和List、ArrayList集合都有一个重大的缺陷,就是从数组的中间位置删除或插入一个元素需要付出很大的代价,其原因是数组中处于被删除元素之后的所有元素都要向数组的前端移动。
    2、LinkedList(底层是由链表实现的)基于链表的数据结构,很好的解决了数组删除插入效率低的问题,且不用动态的扩充数组的长度。
    3、LinkedList的优点:插入、删除元素效率比较高;缺点:访问效率比较低。
  • HashTable哈希表(散列表)
    概念:不定长的二进制数据通过哈希函数映射到一个较短的二进制数据集,即Key通过HashFunction函数获得HashCode
    装填因子:α=n/m=0.72 ,存储的数据N和空间大小M
    然后通过哈希桶算法,HashCode分段,每一段都是一个桶结构,一般是HashCode直接取余。
    桶结构会加剧冲突,解决冲突使用拉链法,将产生冲突的元素建立一个单链表,并将头指针地址存储至Hash表对应桶的位置。这样定位到Hash表桶的位置后可通过遍历单链表的形式来查找元素。
    1、Key—Value形式存取,无序,类型Object,需要类型转换。
    2、Hashtable查询速度快,而添加速度相对慢
    3、Hashtable中的数据实际存储在内部的一个数据桶里(bucket结构体数组),容量固定,根据数组索引获取值。

性能排序:

插入性能: LinkedList > Dictionary > HashTable > List
遍历性能:List > LinkedList > Dictionary > HashTable
删除性能: Dictionary > LinkedList > HashTable > List

四、C#中常规容器和泛型容器有什么区别,哪种效率高?

不带泛型的容器需要装箱和拆箱,操作速度慢,所以泛型容器效率更高,数据类型更安全。

五、有哪些常见的数值类?

  • 简单值类型:包括 整数类型、实数类型、字符类型、布尔类型
  • 复合值类型:包括 结构类型、枚举类型

六、泛型是什么

多个代码对 【不同数据类型】 执行 【相同指令】的情况
泛型:多个类型共享一组代码
泛型允许类型参数化,泛型类型是类型的模板
5种泛型:类、结构、接口、委托、方法
类型占位符 T 来表示泛型

泛型类不是实际的类,而是类的模板
从泛型类型创建实例
声明泛型类型→通过提供【真实类型】创建构造函数类型→从构造类型创建实例
泛型类型参数

  • 性能:泛型不会强行对值类型进行装箱和拆箱,或对引用类型进行向下强制类型转换,所以性能得到提高
  • 安全:通过知道使用泛型定义的变量的类型限制,编译器可以在一定程度上验证类型假设,所以泛型提高了程序的类型安全。

七、C#中unsafe关键字是用来做什么的?什么场合下使用?

非托管代码才需要这个关键字一般用在带指针操作的场合。
项目背包系统的任务装备栏使用到。

1.基本概念

默认情况下,C#是不支持 指针 的,unsafe 关键词用于在C#表示不安全的上下文,如果想要在C#中进行任何和指针相关的操作,就必须配合unsafe关键词使用。

在公共语言运行时(CLR)中,不安全代码是指无法验证的代码。

C# 中的不安全代码不一定是危险的,只是 CLR 无法验证该代码的安全性。因此,CLR 将仅执行完全信任的程序集中的不安全代码。

如果使用不安全代码,应该负责确保代码不会引发安全风险或指针错误

2.基本使用

如果想要在Unity中正常使用C#中的unsafe关键词进行程序编写,我们必须在Unity的 Player Settings 中的 Other Settings 中将 Allow 'unsafe' Code 选项勾选上

12.22 C#基础_第1张图片

unsafe关键词的基本用法:

1.用于修饰函数

12.22 C#基础_第2张图片

2.用于修饰代码块

12.22 C#基础_第3张图片

3.用于修饰成员变量

12.22 C#基础_第4张图片

4.用于修饰类

12.22 C#基础_第5张图片

总结:unsafe 的使用虽然能让我们在C#中使用指针,但是会存在安全风险和稳定性风险,如果没有特殊需求,请尽量避免在C#中使用 unsafe。

八、C#中ref和out关键字有什么区别?

ref修饰引用参数。参数必须赋值,在内部可改可不改,带回返回值,又进又出
out修饰输出参数。参数可以不赋值,在内部必须修改该值,带回返回值之前必须明确赋值。

引用参数和输出参数不会创建新的存储位置

如果ref参数是值类型,原先的值类型数据,会随着方法里的数据改变而改变,
如果ref参数值引用类型,方法里重新赋值后,原对象堆中数据会改变,如果对引用类型再次创建新对象并赋值给ref参数,引用地址会重新指向新对象堆数据。方法结束后形参和新对象都会消失。实参还是指向原始对象,值不够数据改变了
 

请看:把 ref 和 out 关键字说透_out关键字的作用-CSDN博客

感谢大佬!

你可能感兴趣的:(c#,开发语言)