C#编程基础(中级)(三)——堆和栈,值类型和引用类型,继承,虚函数,隐藏方法,this和base关键字的作用

1.堆和栈

内存空间分为堆空间栈空间。栈空间比较,但是读取速度;堆空间比较,但是读取速度

  • 栈:数据只能从栈的顶端插入和删除;
  • 堆:堆是一块内存区域,堆里的内存能够以任意顺序存入和移除,程序对堆里存储内容进行的是引用

GC Garbage Collector 垃圾回收器
CLR的GC就是内存管理机制,会删除堆中已经没有引用的内容,使得空间可以重复使用。

2.值类型和引用类型

  • 值类型:整数,bool,struct,char,小数
  • 引用类型:string,数组,自定义的类,内置的类

值类型只需要一段单独的内存,用于存储实际的数据(单独定义的时候放在栈中)。
引用类型需要两端内存——第一段存储食记的数据,它总是位于堆中;第二段是一个引用,指向数据在堆中的存放位置。

注意:
当我们使用引用类型赋值的时候,其实是赋值的引用类型的引用(即将栈中的内存地址赋值,从而改变其对应的引用)。
如果数组是一个值类型的数组,那么数组中直接存储值;如果是一个引用类型的数组(数组中存储的是引用类型),那么数组中存储的是引用(内存地址)

class Vector3
{
	public int x, y, z;
}

注意对以下五个例子的理解

class Program
{
	static void Main(string[] args)
	{
		Test1();
		Test2();
		Test3();
		Test4();
		Test5();
	}
	static void Test1()
    {
        int i = 34;
        int j = 34;
        int temp = 34;
        char c = 'a';
        bool b = true;
    }
    static void Test2()
    {
        int i = 34;
        int j = 234;
        string name = "LJY";
    }
    static void Test3()
    {
        string name = "LJY";
        string name2 = "Goddy";
        name = name2;
        name = "Blueekyyy";
    }
    static void Test4()
    {
        Vector3 v = new Vector3();
        v.x = 100;
        v.y = 100;
        v.z = 100;
        Vector3 v2 = new Vector3();
        v2.x = 200;
        v2.y = 200;
        v2.z = 200;
        v2 = v;
        v2.x = 300;
        Console.WriteLine(v.x);
    }
    static void Test5()
    {
        Vector3[] vArray = new Vector3[] { new Vector3(), new Vector3(), new Vector3() };
        Vector3 v1 = vArray[0];
        vArray[0].x = 100;
        v1.x = 200;
        Console.WriteLine(vArray[0].x);
    }

3.继承

实现继承
表示一个类型派生于一个基类型,它拥有该基类型的所有成员字段和函数。在实现继承中,派生类型采用基类型的每个函数的实现代码,除非在派生类型的定义中指定重写某个函数的实现代码。

接口继承
表示一个类型只继承了函数的签名没有继承任何实现代码。在需要指定该类型具有某些可用的特性时,最好使用这种类型的继承。

注意:
父类声明的对象,可以使用子类去构造,此时该对象虽然是使用父类进行声明的,但因为其使用了子类构造,所以本质上是一个子类类型的对象,可以通过强制类型转换成子类类型。但子类声明的对象不可以通过父类构造,因为子类的功能比父类强大,父类较小。

一个对象是什么类型的,主要看它是通过什么构造的(通过子类构造就是子类类型,通过父类构造就是父类类型)。

例如:

//父类是Enemy,子类是Boss

static void Main(string[] args)
{
	Enemy enemy;
	enemy = new Boss();//父类声明的对象,可以使用子类去构造
	Boss boss = (Boss)enemy;//使用强制类型转换将对象转换为子类类型
	boss.Attack();//从而该父类声明的变量可以调用子类中的函数
}

4.虚函数

把一个基类函数声明为virtual,就可以在任何派生类中重写该函数。在派生类中重写另外一个函数时,要使用override关键字显示声明。我们在子类里面重写虚函数之后,用子类声明并构造的对象调用时,调用的都是重写之后的方法。但如果用父类声明并构造的对象调用该方法,调用的还是父类中原本的虚函数(跟子类没有任何关系)。

注意:
成员修饰符virtual必须位于成员类型和名称之前

5.隐藏方法

如果签名相同(即)的方法在基类和派生类中都进行了声明,但是该方法没有分别声明为virtual和override,派生类就会隐藏基类方法。要使用new关键字进行声明。
例如:

class Vector3
{
    public int x, y, z;
    public void Move()
    {

    }
}

class Vector4:Vector3
{
    static new void Move()
    {

    }
}

当子类里面有一个签名和父类相同的方法时,就会把父类中的方法隐藏。如果使用子类声明的对象,调用隐藏方法会调用子类的,如果使用父类声明的对象,调用隐藏方法会调用父类的

6.this和base关键字的作用

this可以访问当前类中定义的字段、属性和方法,有没有this都可以访问(有this可以让编译器给出提示),另外当方法的参数与字段重名的时候,使用this可以表明访问的是类中的字段,base可以调用父类中公有方法和字段,有没有base都可以访问(但加上base.IED工具会给出提示,把所有可以调用的字段和方法罗列出来方便选择)。

【当方法的参数与字段重名的时候,使用this可以表明访问的是类中的字段】例如:

class Vector3
{
    public int x, y, z;
    public void Set(int x,int y,int z)
    {
        this.x = x;
        this.y = y;
        this.z = z;
    }
}

你可能感兴趣的:(C#编程基础,C#)