Relationships are defined [09] C # learning methods, and call stack calls and commissioning (lower) method

Courseware

Here Insert Picture Description
Here Insert Picture Description
Here Insert Picture Description
Here Insert Picture Description
Here Insert Picture Description

Constructor

1. What is the constructor?

Constructor, also known as the constructor , a member of the type (there are a dozen types of members), we usually say constructor means understanding the narrow sense: instance constructor (instance constructor).

2. Why do we need constructors?

Examples of the constructor function:It used to construct the internal structure of this example, in memory.
When the class value is required in some instances a field where a predetermined fixed value or when the need to create an instance, a custom configuration can help us to achieve this objective.

3. The constructor declaration

note:Constructor does not return type(Data not need to return any results, only the memory block can be configured good);Constructor name must match the type nameYou must be with "()"

(1) the default constructor

Here Insert Picture Description

(2) without constructor arguments

Here Insert Picture Description

(3) a constructor parameters

Here Insert Picture Description

Builders (4) + parameterized constructor with no arguments

Here Insert Picture Description

4. constructor call

Student stu = new Student();
//“( )"这对括号就是在调用构造器了

The memory mechanism instance constructor

//实例构造器的内存机理
class Program
{
	static void Main(string[] args)
	{
//创建实例并赋值给局部变量"stu",调用构造器,传入构造器所需参数		
		Student stu = new Student(1,"Mr Okay");   
	}
}
//声明类
class Student     
{
//声明带参数的构造器	
	public Student(int ID,string Name)   
	{
		this.ID = ID;               
		this.Name = Name;
	}
//创建实例字段	
	public int ID;          
	public string Name;
}

(1) Computer see "stu" is a method declared in a local variable , and is a type of a reference variable, for immediately cut out 4 bytes of memory space in the stack, ready to point to an instance where the memory the address of.

(2)"new Student"表示为该类创建一个实例,计算机立刻去堆上寻找空余位置,找到之后根据类中定义的实例字段分配出相应空间:int—需4个字节;string—需4个字节,但此时并没有四四分开,而是8个字节连在一起的,因为还没有执行到调用构造器。构造器是用来构建该实例在内存中的内部结构的

(3)"( )“表示调用构造器,此时自定义构造器登场,开始对实例所在的内存块进行分配和初始化。分配:int ID—4个字节;string—4个字节;初始化:int—值为1,转化成二进制存入所处内存块;string—值为"Mr Okay”,但由于string是一个引用类型的变量,所以其所属的4个字节的内存空间用以存储这个字段的实例的所在地址。在堆上寻找一块内存空间存储"Mr Okay"。并将地址传回。

(4)将“stu"的实例地址,传回给变量"stu"。

6.构造器内存机理的图片说明

Here Insert Picture Description

7.一个小技巧

Ctrl + 两下tab键,会自动准备好一个默认构造器,只需往里添加参数即可。

方法的重载(overload)

1.什么是方法的重载?

是指在一个类中定义多个同名的方法,但要求每个方法具有不同的参数的类型或参数的个数。
换言之也就是:类中的多个方法的方法名可以相同,但它们的方法签名必须不同。

2.什么是方法签名?

方法签名由方法的名称、类型形参的个数和它的每一个形参(按从左到右的顺序)的类型和种类(值、引用或输出) 组成。

即,方法签名由4个部分组成:
(1)方法名
(2)方法的类型形参 *
(3)方法形式参数的类型
(4)方法形式参数的种类(值参数,引用参数,输出形参)

(2)比较高级,先不做详细了解

3.如何声明一个带有重载的方法?

Here Insert Picture Description

4.重载决策

指调用方法时到底调用哪个重载,这个不用担心,编译器会根据传入的实参自动决定。

如何对方法进行debug

1.debug的目的

(1)排除bug
(2)通过debug执行动态程序,从而了解程序内部是如何运行的

2.debug的流程

(1)设置断点(break point)
一旦设置好断点,在调试模式下运行程序,程序就会在断点处停止,等待调试者对程序的观察。

(2)观察方法调用时的调用栈(call stack)
这里的调用栈不等同于内存栈,但两者之间存在紧密的映射关系:调用栈越深,占用内存栈的资源就越多。

调用栈的主要功能是存放返回地址

(3)三种调试方法(step into;step over;step out)
step into(F11) :单步执行程序;走进正在被调用的函数中看看具体是怎么回事儿,是最仔细的调试方法。

step over(F100) :逐过程;不会走进方法,整个方法会一步执行,直接给出最后的返回结果。
step over 和 step into 结合使用,前者确定bug大范围,后者确定root cause。

step out (shift + F11):跳出;当进入一个方法准备执行时,点击step out可跳出该方法,返回原调用该方法的语句处执行下一步语句。

当程序特别大时,一个类调用另一个类的方法,而这两个类可能根本就不在同一个文件里,要想知道是哪个类调用了当前方法,step out 可直接返回去,非常方便。

(4)观察局部变量的值变化
可以把光标移动在变量上面直接观察;
可以通过locals窗口一览;
Here Insert Picture Description
也可以定住小别针。(会根据程序的调试进程更新)
Here Insert Picture Description

3.一段适合观察debug流程的代码

//递归算法
class Calculator
{
	public double GetCircleArea(double r)
	{
		return Math.PI * r * r;
	}
	public double GetCylinderVolume(double r,double h)
	{
		double a = GetCircleArea(r)return a * h;
	}
	public double GetConeVolume(double r,double h)
	{
		double cv = GetCylinderVolume(r,h);
		return cv / 3;
	}
}

方法的调用与栈的关系

这里的栈,指的是内存栈

1.什么是stack frame ?

stack frame(栈帧),可理解为一个方法在被调用时在栈内存中的布局

2.主调函数与被调函数

被调函数是指被调用的函数;
主调函数是指调用该函数的函数;

主调函数,是一个相对的概念,它是相当于被调函数来说的。在C#中,Main()方法是程序的入口,因此接下来要调用的其他任何函数都必须在Main()函数中调用,此时Main()函数就是主调函数。

主调函数不是只有Main()函数,其他函数只要在内部调用了任何函数,那么它也就是一个主调函数。

3.一个原则

谁调用这个参数,谁负责管理这个参数(往栈里压内存)

4.详细的示例说明

我们还是以这段代码为例,说明方法的调用与栈内存的关系,并同时观察调用栈与内存栈的映射关系。

(注意:表格左侧部分表示栈内存分配情况,也就是方法的stack frame,右侧区域起标签作用。)
Here Insert Picture Description

(1)栈内存由高字节位向低字节位发展,(发展到最低限度,就会stack over flow),底部蓝色部分表示已被其他程序占用的内存。Main()方法有其自己的stack frame,具体占多大内存在这里不做讨论,把这部分刷成绿色,右侧部分刷成同色,并注以Main做标记。

(2)开始执行程序,当Main()方法调用GetConeVolume()方法时需要传入两个double类型的参数(参数也是变量,局部变量需压入栈中):double r,double h;由于C#中规定主调者管理参数,所以根据 “谁调用参数,谁管理参数” 的原则,Main()方法负责把这个两个参数压入栈;且由于C#规定按从左到右的顺序压入参数,所以是先压double r,将其8个字节刷成黄色,再压double h,将其8个字节刷成草绿色。所有这些部分(Main自己的栈内存,这两个参数的栈内存)都是Main()方法的stack frame。(最左侧橙色区域是操作系统所用内存)
Here Insert Picture Description
(3)继续执行,进入GetConeVolume()方法,可看到locals窗口显示此方法有三个变量需压入栈中,r,h作为参数已被Main()压入,所以只需压入cv即可,cv也是double类型的变量,分配其8个字节。

(4)继续执行,准备进入GetCylinderVolume()方法,和刚刚相同,此时GetConeVolume()方法是主调者,GetCylinderVolume()是被调者,主调者负责压入参数。
Here Insert Picture Description
(5)继续执行,进入GetCylinderVolume()方法,它作为主调者调用GetCircleArea()方法,观察locals变量表,现在只需压入 " a " 变量。

(6)继续执行,准备进入GetCircleArea()方法,只需压入一个double类型的参数r即可;依然是谁调用谁管理,这部分也是GetCylinderVolume()的stack frame。

(7)继续执行,进入GetCircleArea()方法,进行最后一层调用。该方法的参数已被它的主调者压入栈中。

小问题:那GetCircleArea()方法是不是就不在栈中占内存了呢?
不是的,一个方法即使没有局部变量,它还是需要往栈里压其他东西,比如说:当前方法执行完毕后返回到的方法的内存地址。
该图只是重点表示参数和局部变量的内存。

刷一部分表示GetCircleArea()方法的stack frame。
Here Insert Picture Description
(8)执行完GetCircleArea()方法后,会产生一个返回值,此时程序会拿着这个返回值准备返回到调用GetCircleArea()的方法中去. At this point the call stack deepest.
Here Insert Picture Description
NOTE: The return value is generally present among the CPU registers (registers are an important part of the CPU, which is to be understood that the CPU built in very fast memory)

(9) calls GetCircleArea () is GetCylinderVolume () method , return to this method , the layer of less observe the call stack, as it has been returned to the floor, then call GetCircleArea () method has been completed, stack frame is emptied, which parameters are not used, so just pressed in a parameter r is also cleared.
Here Insert Picture Description
(10) With return method is a layer stack memory is gradually pop up, call stack gradually faded, until the end of the program, the program runs all occupied stack memory is cleared .
Here Insert Picture Description
Stack faded: Here Insert Picture Description
end the program:
Here Insert Picture Description

A case where stack over flow may occur

Method call hierarchy is too deep, and did not return, a layer of the parameter pressed into the stack, but could not return, leading to the top of the stack grow indefinitely, until the stack explosion.

Published 29 original articles · won praise 3 · Views 954

Guess you like

Origin blog.csdn.net/weixin_44813932/article/details/103770653