第8、9节 方法的定义、调用与调试
方法的由来
- 方法(method)的前身是C/C++语言的函数(function)
1)方法是面向对象范畴的概念,在非面向对象语言中仍然称为函数
2)使用C/C++语言做对比
C语言中的函数
#include <stdio.h>
//C语言中的Function
double Add(double a, double b)
{
return a + b;
}
int main()
{
double x = 3.0;
double y = 5.0;
double result = x + y;
printf("%f+%f=%f", x, y, result);
}
C++语言中的函数
#include <iostream>
//C++语言的函数
double Add(double a, double b)
{
return a + b;
}
int main()
{
double x = 3.0;
double y = 5.0;
double result = Add(x,y);
std::cout << x <<"+" << y << "=" << result; //std名称空间,::访问名称空间中的元素
return 0;
}
- 永远都是类(或结构体)的成员
1)C#语言中函数不可能独立于类(或结构体)之外
2)只有作为类(结构体)的成员时才被称为方法
3)C++中是可以的,称为“全局函数” - 是类(或结构体)最基本的成员之一
1)最基本的成员只有两个——字段与方法(成员变量与成员方法),本质还是数据 + 算法
2)方法表示类(结构体)“能做什么事情” - 为什么需要方法和函数
1)目的1:隐藏复杂的逻辑
2)目的2:复用(reuse,重用)
3)示例:计算圆面积、圆柱体积、圆锥体积
方法的复用,可以方便大型程序统一修改
class Calulator
{
public double GetCircleArea(double r)
{
return Math.PI * r * r;
}
public double GetCylinderVolume(double r, double h)
{
return GetCircleArea(r) * h;
}
public double GetConeVolume(double r, double h)
{
return GetCylinderVolume(r, h) / 3;
}
}
方法的定义与调用(特别重要)
- 声明方法的语法详解
1)参见C#语言文档(声明/定义不分家)
2)Parameter全称为“formal parameter”,形式上的参数,简称“形参”
3)Parameter是一种变量 - 方法的命名规范
1)大小写规范:Pascal方法,构成标识符的每一个单词的首字母都大写
2)需要以动词或动词短语作为名字 - 重温静态(static)方法和实例方法
静态方法和类绑定,而实例方法和实例绑定。 - 调用方法
1)Argument中文C#文档的官方译法为“实际参数”,简称“实参”,可理解为调用方法时的真实条件
2)调用方法时的argument列表要与定义方法时的parameter列表相匹配
C#是强类型语言,argument是值、parameter是变量,值与变量一定要匹配,不然编译器会报错
注: 在调用方法的时候,用实参(argument)给形参(parameter)赋值。
构造器(一种特殊的方法)
- 构造器(constructor)是类型的成员之一
注:构造函数译为构造器,成员函数译为方法,本质上都是函数 - 狭义的构造器指的是“实例构造器”(instance constructor)
- 如何调用构造器
Student stu = new Student();
//调用实例的无参构造器或者默认构造器
Student stu2 = new Student(2,"Wang");
//调用实例的有参构造器
- 声明构造器(无返回值类型)
- 构造器的内存原理
特别注意带参数的构造器,对于字符串类型的参数,需要在内存中再开辟一个实例的空间,将该部分的地址存储在引用类型字段的存储空间中。
构造器的声明和调用,举例:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConstructorExample
{
class Program
{
static void Main(string[] args)
{
Student stu = new Student();
//等号左端是声明变量stu,等号右端是创建一个Student的实例
//()是调用Student里面的构造器
//若Student中没有设定构造器,则有默认的构造器将ID和Name都置为0
Console.WriteLine(stu.ID);
Console.WriteLine(stu.Name);
Console.WriteLine("==========================");
Student stu2 = new Student(2,"Wang");
Console.WriteLine(stu2.ID);
Console.WriteLine(stu2.Name);
}
}
class Student
{
//自定义有参数的构造器
public Student(int initId, string initName)
{
this.ID = initId;
this.Name = initName;
}
//自定义无参数的构造器
public Student()
{
this.ID = 1;
this.Name = "No name";
}
public int ID;
public string Name;
}
}
注:倘若某个类中已经声明了有参数的构造器,则无参的默认构造器就无法使用,要想继续使用无参的构造器,需要在该类中自定义一个无参的构造器。
方法的重载(Overload)
- 调用重载方法的示例
Console.WriteLine( )方法可以打印出不同类型的参数,是因为WriteLine方法的重载。 - 声明带有重载的方法
1)方法签名(method signature)由方法的名称、类型形参的个数和方法的每一个形参(按从左到右的顺序)的类型和种类(值、引用或输出)组成。方法签名不包含返回类型
类型形参
public int Add<T>(ref int a, out int b, int c)
// <T>是类型参数
形参的种类:值参数、引用参数、输出参数
public int Add(ref int a, out int b, int c) // a是引用参数,b是输出参数,c是值参数
{
b = 1;
return a + b + c;
}
2)实例构造函数签名由它的每一个形参(按从左到右的顺序)的类型和种类(值、引用或输出)组成。
3)重载决策(到底调用哪一个重载):用于在给定了参数列表和一组候选函数成员的情况下,选择一个最佳函数成员来实施调用。
如何对方法进行debug
- 设置断点(breakpoint)
- 观察方法调用时的调用堆栈(call stack)
- Step-in, Step-over, Step-out
step-in:f11(一步一步仔细地调试),step-over:f10(快速调试),step-out:shift+f11(直接回到调用该部分的位置上) - 观察局部变量的值与变化
方法的调用与栈(难)
一般,函数的返回值存放在寄存器里面;方法在哪个函数里面调用的,参数变量由该函数管理;C#语言由左向右存放参数