文章目录
实验目的
理解继承和多态,通过上机实验掌握基类、派生类、构造函数、析构函数、重载方法和虚构方法。学习如何用C#语言实现构建基类和派生类并掌握通过多态性来处理基类和派生类的对象行为。
实验内容
P5_1(基类和派生类)
声明派生类
public class Bus : Automobile
构造函数中可以直接使用基类中的成员
代码如下:
using System;
namespace P5_1
{
class Program
{
static void Main()
{
Bus b1 = new Bus();
Console.WriteLine("客车行驶1000公里需{0}小时",b1.Run(1000));
Truck t1 = new Truck();
Console.WriteLine("卡车行驶1000公里需{0}小时",t1.Run(1000));
}
}
public class Automobile
{
protected float speed;//私有字段speed
public float Speed//用Speed属性对私有字段speed进行封装
{
get { return speed; }//进行值的读取
}
private float weight;//私有字段weight
public float Weight//用Weight属性对私有字段weight进行封装
{
get { return weight; }//进行值的读取
set { weight = value; }//进行值的设置
}
public float Run(float distance)//计算时间的方法
{
return distance / speed;
}
}
public class Bus : Automobile
{
private int passengers;//私有字段passengers
public int Passenger//用Passenger属性对私有字段passenger进行封装
{
get { return passengers; }//进行值的读取
set { passengers = value; }//进行值的设置
}
public Bus()//构造函数
{
passengers = 20;
speed = 60;
Weight = 10;
}
}
public class Truck : Automobile
{
private float load;//私有字段load
public float Load//用Load属性对私有字段load进行封装
{
get { return load; }//进行值的读取
set { load = value; }//进行值的设置
}
public Truck()//构造函数
{
load = 30;
speed = 50;
Weight = 15;
}
}
}
输出:
客车行驶1000公里需16.666666小时
卡车行驶1000公里需20小时
P5_3(对象的生命周期)
创建时自顶向下调用各级构造函数,销毁时自底向上调用各级析构函数
代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace review
{
class Program
{
public static void Main()
{
Son s1 = new Son();
System.GC.Collect();
}
}
public class Grandsire
{
public Grandsire()
{
Console.WriteLine("调用Grandsire的构造函数");
}
~Grandsire()
{
Console.WriteLine("调用Grandsire的析构函数");
}
}
public class Father : Grandsire
{
public Father()
{
Console.WriteLine("调用Father的构造函数");
}
~Father()
{
Console.WriteLine("调用Father的析构函数");
}
}
public class Son : Father
{
public Son()
{
Console.WriteLine("调用Son的构造函数");
}
~Son()
{
Console.WriteLine("调用Son的析构函数");
}
}
}
输出:
调用Grandsire的构造函数
调用Father的构造函数
调用Son的构造函数
调用Son的析构函数
调用Father的析构函数
调用Grandsire的析构函数
P5_4(重载方法和虚构方法)
按照多态性的思想,对象可以根据自己的方式来提供服务。需要将基类的方法定义为虚拟方法(用virtual修饰),将派生类中的对应方法定义为重载方法(用override修饰),程序就能根据对象的实际类型调用对应的方法。
代码如下:
using System;
namespace P5_4
{
class Program
{
static void Main()
{
foreach (Automobile a in GetAutos())
{
a.Speak();
Console.WriteLine("{0}行驶1000公里需{1}小时",a.Name,a.Run(1000));
}
}
static Automobile[] GetAutos()
{
Automobile[] autos = new Automobile[4];
autos[0] = new Bus("客车", 20);
autos[1] = new Truck("东风卡车", 30);
autos[2] = new Truck("黄河卡车", 45);
autos[3] = new Automobile("汽车", 80, 3);
return autos;
}
}
public class Automobile//定义基类
{
private string name;//私有字段name
public string Name//用Name属性对私有字段name进行封装
{
get { return name; }
}
private float speed;//私有字段speed
public float Speed//用Speed属性对私有字段speed进行封装
{
get { return speed; }
}
private float weight;//私有字段weight
public float Weight//用Weight属性对私有字段weight进行封装
{
get { return weight; }
set { weight = value; }
}
public Automobile(string name, float speed,float weight)//定义构造函数进行初始化
{
this.name = name;
this.speed = speed;
this.weight = weight;
}
public virtual float Run(float distance)//虚拟方法
{
return distance / speed;
}
public virtual void Speak()//虚拟方法
{
Console.WriteLine("汽车鸣笛……");
}
}
public class Bus : Automobile//定义派生类Bus
{
private int passengers;//私有字段passengers,派生类可以访问
public int Passengers//用Passengers属性对私有字段passengers进行封装
{
get { return passengers; }
set { passengers = value; }//设置值
}
public Bus(string name,int passengers) : base(name, 60, 10)//构造函数进行初始化,引用基类的成员
{
this.passengers = passengers;
}
public override void Speak()//重载Speak方法
{
Console.WriteLine("嘀……嘀……");
}
}
public class Truck : Automobile//定义基类Truck
{
private float load;//私有字段load,派生类可以访问
public float Load//用Load属性对私有字段load进行封装
{
get { return load; }
set { load = value; }//设置值
}
public Truck(string name,int load) : base(name, 50, 15)//构造函数进行初始化,引用基类成员
{
this.load = load;
}
public override float Run(float distance)//重载Run方法
{
return (1 + load / Weight / 2) * base.Run(distance);
}
public override void Speak()//重载Speak方法
{
Console.WriteLine("叭……叭……");
}
}
}
输出:
嘀……嘀……
客车行驶1000公里需16.666666小时
叭……叭……
东风卡车行驶1000公里需40小时
叭……叭……
黄河卡车行驶1000公里需50小时
汽车鸣笛……
汽车行驶1000公里需12.5小时
在Point类基础上,实现一个直线段类Line
基于point定义了line,并通过CallLength方法计算出线段的长度
最终通过program输出线段端点的坐标及线段的长度
Point类:
using System;
using System.Collections.Generic;
using System.Text;
namespace Line
{
class point
{
public double x, y;
public point(double a,double b)
{
x = a;
y = b;
}
}
}
Line类:
using System;
using System.Collections.Generic;
using System.Text;
namespace Line
{
public class line
{
private point pnt1, pnt2;
private double len;
public line(double a1, double a2, double b1, double b2)
{
pnt1 = new point(a1, a2);
pnt2 = new point(b1, b2);
}
public void CallLength()
{
len =Math.Sqrt((pnt1.x - pnt2.x) * (pnt1.x - pnt2.x) + (pnt1.y - pnt2.y) * (pnt1.y - pnt2.y));
}
public void write()
{
Console.WriteLine("线段的端点1是 ({0},{1}),端点2是 ({2},{3})", pnt1.x, pnt1.y, pnt2.x, pnt2.y);
}
public void writelen()
{
Console.WriteLine("线段的长度是 {0}",len);
}
}
}
Program:
using System;
namespace Line
{
class Program
{
static void Main()
{
line line1 = new line(1, 4, 4, 8);
line1.write();
line1.CallLength();
line1.writelen();
}
}
}
输出:
线段的端点1是 (1,4),端点2是 (4,8)
线段的长度是 5
在Point类基础上,实现一个矩形类Rect
基于point定义了rect,并通过CallLength方法计算出矩形的周长
最终通过program输出矩形左上角和右下角的坐标及矩形的周长
Point类:
using System;
using System.Collections.Generic;
using System.Text;
namespace Rect
{
class point
{
public double x, y;
public point(double a, double b)
{
x = a;
y = b;
}
}
}
Rect类:
using System;
using System.Collections.Generic;
using System.Text;
namespace Rect
{
public class rect
{
private point pnt1, pnt2;
private double len;
public rect(double a1,double a2,double b1,double b2)
{
pnt1 = new point(a1, a2);
pnt2 = new point(b1, b2);
}
public void CallLength()
{
len = 2 * (Math.Abs(pnt1.x - pnt2.x) + Math.Abs(pnt1.y - pnt2.y));
}
public void write()
{
Console.WriteLine("矩形的左上角是 ({0},{1}),右下角是 ({2},{3})", pnt1.x, pnt1.y, pnt2.x, pnt2.y);
}
public void writelen()
{
Console.WriteLine("矩形的周长是 {0}", len);
}
}
}
Program:
using System;
namespace Rect
{
class Program
{
static void Main()
{
rect rect1 = new rect(2, 5, 7, 20);
rect1.write();
rect1.CallLength();
rect1.writelen();
}
}
}
输出:
矩形的左上角是 (2,5),右下角是 (7,20)
矩形的周长是 40
Point、Line、Rect类基础上,实现一个它们共同的基类形状类Shape
基类shape定义了len和虚拟方法CallLength、
派生类中分别定义了各自的构造函数并重载了CallLength方法
Shape及其派生类:
using System;
using System.Collections.Generic;
using System.Text;
namespace Shape
{
/// <summary>
/// 定义基类
/// </summary>
public class shape
{
private double len; //私有字段len
public double Len//用Len属性对私有字段len进行封装
{
get { return len; }
set { len = value; }
}
public virtual void CallLength()//定义虚拟方法
{
len = 0;
}
}
/// <summary>
/// 派生类point
/// </summary>
public class point: shape
{
public double x, y;
public point (double a ,double b)
{
x = a;
y = b;
}
public override void CallLength()//重构CallLength方法
{
Len = 0;
}
}
/// <summary>
/// 派生类line
/// </summary>
public class line : shape
{
private point pnt1, pnt2;
public line(double a1, double a2, double b1, double b2)
{
pnt1 = new point(a1, a2);
pnt2 = new point(b1, b2);
}
public override void CallLength()//重构CallLength方法
{
Len = Math.Sqrt((pnt1.x - pnt2.x) * (pnt1.x - pnt2.x) + (pnt1.y - pnt2.y) * (pnt1.y - pnt2.y));
}
}
/// <summary>
/// 派生类rect
/// </summary>
public class rect : shape
{
private point pnt1, pnt2;
public rect(double a1, double a2,double b1,double b2)
{
pnt1 = new point(a1, a2);
pnt2 = new point(b1, b2);
}
public override void CallLength()//重构CallLength方法
{
Len = 2 * ((Math.Abs(pnt1.x - pnt2.x)) + (Math.Abs(pnt1.y - pnt2.y)));
}
}
}
Program:
using System;
namespace Shape
{
class Program
{
static void Main()
{
point pnt1 = new point(1, 2);
pnt1.CallLength();
Console.WriteLine("点pnt1的'长度'为{0}", pnt1.Len);
line line1 = new line(1, 4, 4, 8);
line1.CallLength();
Console.WriteLine("线段line1长度为{0}", line1.Len);
rect rect1 = new rect(2, 5, 7, 20);
rect1.CallLength();
Console.WriteLine("矩形rect1的周长为{0}", rect1.Len);
}
}
}
输出:
点pnt1的’长度’为0
线段line1长度为5
矩形rect1的周长为40
总结
派生类能够继承基类的所有成员并增加自己的成员来进行功能扩展。而多态性则由定义的虚拟方法和重载方法体现。在基类中定义的虚拟方法可以在派生类中通过重载方法实现不同派生类所需的不同功能。