文章目录
实验目的
按照建立c#控制台程序的步骤,在vs2015中建立工程,理解类的相关定义及编程方法。
实验内容
- 实现P4_1(静态成员和非静态成员)、P4_2(常量字段和只读字段)、P4_3(方法参数的值传递和引用传递)、P4_5 (构造函数)、P4_6(操作符重载)、P4_8(格式化和解析)
- 实现一个点类Point
- 思考类似实现一个线类Line或者多线类PolyLine
P4_1(静态成员和非静态成员)
成员分为静态成员和非静态成员,静态成员属于类所有,非静态成员属于对象所有。
程序中使用关键字static来定义静态成员
在使用时,静态成员通过类名来访问
注意:
1.静态方法只能使用静态成员
2.实例方法既能使用静态成员也能使用非静态成员
3.如果所有类的所有成员都是静态的,可以使用static定义静态类,例如:Console
代码如下:
using System;
namespace P4_1
{
class Program
{
static void Main()
{
Student.WriteSchoolInfo();
Student s1 = new Student();
s1.name = "王小红";//访问非静态成员
Student s2 = new Student();
s2.name = "周军";//访问非静态成员
s2.Department = "某系";//访问非静态成员
Student.School = "野鸡大学";//访问静态成员
Student.WriteSchoolInfo();
s1.WritePersonalInfo();
s2.WritePersonalInfo();
}
}
public class Student
{
public static string School = "野鸡大学";//定义静态成员
public string name, Department = "某系";//定义非静态成员
public int age;
public void WritePersonalInfo()
{
Console.WriteLine("{0} {1} {2}", School, Department, name);
}
public static void WriteSchoolInfo()
{
Console.WriteLine(School);
}
}
}
输出:
野鸡大学
野鸡大学
野鸡大学 某系 王小红
野鸡大学 某系 周军
P4_2(常量字段和只读字段)
常量字段
用const定义:public const double PI = 3.1415927;
通过类名访问:double p = 2 * Circle.PI * c.r;
只读字段
用readonly定义:public readonly int id;
通过对象访问:Console.WriteLine(c.id);
代码如下:
using System;
namespace P4_2
{
class Program
{
static void Main()
{
for (int i = 0; i < 5; i++)
{
BankCard c = new BankCard();
Console.WriteLine(c.id);
}
}
}
public class BankCard
{
public readonly int id;//定义只读字段
private static int count = 0;//静态字段记录已有的对象数量
public BankCard()
{
id = ++count;//id值递增
}
}
}
输出:
1
2
3
4
5
P4_3(方法参数的值传递和引用传递)
值传递:实参的值将被复制一份给形参,方法代码中对形参值的修改并不会影响到实参
引用传递:实参和形参会指向同一个对象,此时形参是实参的“引用“。方法中修改形参的值时,实参的值也会发生相应的变化。
引用传递的方法参数需要通过ref关键字加以修饰
代码如下:
using System;
namespace P4_3
{
class Program
{
static void Main()
{
int a = 10, b = 20;
ValueSwap(a, b);//值传递的Swap方法
Console.WriteLine("值传递:a = {0}, b = {1}", a, b);
ReferenceSwap(ref a, ref b);//引用传递的Swap方法
Console.WriteLine("引用传递:a = {0}, b = {1}", a, b);
}
public static void ValueSwap(int x, int y)//声明值传递的Swap方法
{
int z = x;
x = y;
y = z;
}
public static void ReferenceSwap(ref int x, ref int y)//通过ref关键字加以修饰,声明引用传递的Swap方法
{
int z = x;
x = y;
y = z;
}
}
}
输出:
值传递:a = 10, b = 20
引用传递:a = 20, b = 10
P4_5 (构造函数)
构造函数:
类前面需要加public,构造函数与类同名,主要用于完成对象的初始化工作
静态构造函数:
静态构造函数为类的所有对象共享,并且只在首次使用该类时被调用
代码如下:
using System;
namespace P4_5
{
class Program
{
static void Main()
{
Student s1 = new Student("王小红");//实例构造函数加1,静态构造函数加1
Student s2 = new Student("周军");//实例构造函数加1
s1 = new Student("Jerry");//实例构造函数加1
}
}
public class Student
{
public static int objects = 0, classes = 0;//计数变量
public string name;
public Student(string n)//实例构造函数
{
name = n;
Console.WriteLine("对象计数:{0}", ++objects);
}
static Student()//静态构造函数
{
Console.WriteLine("类计数:{0}", ++classes);
}
}
}
输出:
类计数:1
对象计数:1
对象计数:2
对象计数:3
P4_6(操作符重载)
使用operator关键词进行操作符的重载
for循环中从50至100遍历每一个数
利用构造函数将对象初始化
通过重载后的true和false利用if直接判断是否为素数
如果是素数,将i显示转换为整数后输出
将Prime对象显示转换为p.x
重载true判断条件中写入素数的判断算法,实现利用if判断素数
重载false与重载true方法类似
重载‘+’‘-’符号在main函数中没有用到
代码如下:
using System;
namespace P4_6
{
class Program
{
static void Main()
{
for (uint i = 50; i <= 100; i++)
{
Prime p1 = new Prime(i);
if (p1)
Console.WriteLine((uint)p1);//将i显式转换为一个整数
}
}
}
public class Prime
{
public uint x;
public Prime(uint x1)//构造函数
{
x = x1;
}
public static uint operator +(Prime p1, Prime p2)//重载‘+’操作符
{
return p1.x + p2.x;
}
public static int operator -(Prime p1, Prime p2)//重载‘-’操作符
{
return (int)(p1.x - p2.x);
}
public static explicit operator uint(Prime p)//将Prime对象显式转换为一个整数
{
return p.x;
}
public static bool operator true(Prime p)//重载‘true’的判断条件
{
for (uint i = 2; i < p.x / 2; i++)
if (p.x % i == 0)
return false;
return true;
}
public static bool operator false(Prime p)//重载 ‘false’的判断条件
{
for (uint i = 2; i <= p.x / 2; i++)
if (p.x % i == 0)
return true;
return false;
}
}
}
输出:
53
59
61
67
71
73
79
83
89
97
P4_8(格式化和解析)
operator + 和 operator – 重载了‘+’、‘-’操作符
Parse方法通过判断‘+’和‘I’的位置,选取对应位置区间的字符串转换为整型数字,并返回ComplexNumber对象
TryParse方法先同Parse方法判断字符串是否可以转换为复数,如果可以,则更新ComplexNumber的值;否则,不进行更新
Tostring方法将ComplexNumber对象解析为复数的形式
代码如下:
using System;
namespace P4_8
{
class Program
{
static void Main()
{
ComplexNumber c1 = ComplexNumber.Parse("(50+100i)");
ComplexNumber c2;
ComplexNumber.TryParse("(100,300i)", out c2);
Console.WriteLine("{0} + {1} = {2}", c1, c2, c1 + c2);
ComplexNumber.TryParse("(100+300i)", out c2);
Console.WriteLine("{0} + {1} = {2}", c1, c2, c1 + c2);
}
}
public class ComplexNumber
{
public double A = 0, B = 0;
public ComplexNumber(double a, double b)
{
A = a;
B = b;
}
public static ComplexNumber operator +(ComplexNumber c1, ComplexNumber c2)//重载‘+’,实现复数加法
{
return new ComplexNumber(c1.A + c2.A, c1.B + c2.B);
}
public static ComplexNumber operator -(ComplexNumber c1, ComplexNumber c2)//重载‘-’,实现复数减法
{
return new ComplexNumber(c1.A - c2.A, c1.B - c2.B);
}
public static ComplexNumber Parse(string s)
{
if (s == null)
throw new ArgumentNullException();//抛出异常,程序结束
s = s.ToUpper();//将所有小写字母转换为大写字母
int pos1 = s.IndexOf('+');//记下‘+’出现的位置
int pos2 = s.IndexOf('I');//记下‘I’出现的位置
if (pos1 == -1 || pos2 == -1)
throw new FormatException("输入的字符串格式不正确");//‘+’和‘I’出现的位置异常
double a = double.Parse(s.Substring(1, pos1 - 1));//将‘+’前面的字符串转换为数字
double b = double.Parse(s.Substring(pos1 + 1, pos2 - pos1 - 1));//将‘+’和‘I’之间的字符串转换为数字
//double.Parse将字符串转换为double
return new ComplexNumber(a, b);//返回复数的实部和虚部构成复数
}
public static bool TryParse(string s, out ComplexNumber c)//如果可以转换,将结果输出到c;否则,改变c
{
c = new ComplexNumber(0, 0);
if (s == null)
return false;
s = s.ToUpper();
int pos1 = s.IndexOf('+');
int pos2 = s.IndexOf('I');
if (pos1 == -1 || pos2 == -1)
return false;
//以上同Parse方法
string s1 = s.Substring(1, pos1 - 1);
string s2 = s.Substring(pos1 + 1, pos2 - pos1 - 1);
//将实部和虚部分布构成两个字符串
if (pos1 == -1 || pos2 == -1 || !double.TryParse(s1, out c.A) || !double.TryParse(s2, out c.B))//判断字符串是否合法
return false;
else
return true;
}
public override string ToString()//重写了object类的ToString()方法
{
return string.Format("({0}+{1}i)", this.A, this.B);
}
}
}
输出:
(50+100i) + (0+0i) = (50+100i)
(50+100i) + (100+300i) = (150+400i)
实现一个点类Point
构建点类:
using System;
using System.Collections.Generic;
using System.Text;
namespace Plus1
{
class Point
{
private double x, y;
public Point(double a, double b)
{
this.x = a;
this.y = b;
}
public void Move(Point m)
{
this.x += m.x - this.x;
this.y += m.y - this.y;
}
public static bool operator ==(Point a, Point b)
{
if (a.x == b.x && a.y == b.y)
return true;
else return false;
}
public static bool operator !=(Point a, Point b)
{
if (a.x == b.x && a.y == b.y)
return false;
else return true;
}
public void write()
{
Console.WriteLine("({0},{1})", x, y);
}
}
}
using System;
namespace Plus1
{
class Program
{
static void Main()
{
Point p1 = new Point(1, 2);
Console.Write("p1 = ");
p1.write();
Point p2 = new Point(2, 3);
Console.Write("p2 = ");
p2.write();
if (p1 == p2)
Console.WriteLine("两点相等");
else
Console.WriteLine("两点不相等");
Console.WriteLine("将p1移动到p2");
p1.Move(p2);
Console.Write("p1 = ");
p1.write();
if (p1 == p2)
Console.WriteLine("两点相等");
else
Console.WriteLine("两点不相等");
}
}
}
输出:
p1 = (1,2)
p2 = (2,3)
两点不相等
将p1移动到p2
p1 = (2,3)
两点相等
思考类似实现一个线类Line或者多线类PolyLine
构建线类:
using System;
using System.Collections.Generic;
using System.Text;
namespace Plus2
{
public class Line
{
private double x1, x2, y1, y2, k, dis;
public Line(double a1, double a2, double b1, double b2)
{
this.x1 = a1;
this.x2 = a2;
this.y1 = b1;
this.y2 = b2;
this.k = (this.y2 - this.y1) / (this.x2 - this.x1);
this.dis = Math.Sqrt((this.x2 - this.x1) * (this.x2 - this.x1) + (this.y2 - this.y1) * (this.y2 - this.y1));
}
public bool intersect(Line L)
{
//快速排斥实验
if ((this.x1 > this.x2 ? this.x1 : this.x2) < (L.x1 < L.x2 ? L.x1 : L.x2) ||
(this.y1 > this.y2 ? this.y1 : this.y2) < (L.y1 < L.y2 ? L.y1 : L.y2) ||
(L.x1 > L.x2 ? L.x1 : L.x2) < (this.x1 < this.x2 ? this.x1 : this.x2) ||
(L.y1 > L.y2 ? L.y1 : L.y2) < (this.y1 < this.y2 ? this.y1 : this.y2))
{
return false;
}
//跨立实验
if ((((this.x1 - L.x1) * (L.y2 - L.y1) - (this.y1 - L.y1) * (L.x2 - L.x1)) *
((this.x2 - L.x1) * (L.y2 - L.y1) - (this.y2 - L.y1) * (L.x2 - L.x1))) > 0 ||
(((L.x1 - this.x1) * (this.y2 - this.y1) - (L.y1 - this.y1) * (this.x2 - this.x1)) *
((L.x2 - this.x1) * (this.y2 - this.y1) - (L.y2 - this.y1) * (this.x2 - this.x1))) > 0)
{
return false;
}
return true;
}
public static bool operator ==(Line a, Line b)
{
if (a.k == b.k && a.dis == b.dis)
return true;
else return false;
}
public static bool operator !=(Line a, Line b)
{
if (a.k == b.k && a.dis == b.dis)
return false;
else return true;
}
public void write()
{
Console.WriteLine("起点({0},{1}),终点({2},{3})", x1, x2, y1, y2);
}
}
}
using System;
namespace Plus2
{
class Program
{
static void Main()
{
Line L1 = new Line(1, 2, 2, 3);
Console.Write("第一条线段:");
L1.write();
Line L2 = new Line(6, 7, 7, 8);
Console.Write("第二条线段:");
L2.write();
Line L3 = new Line(1, 2, 7, 9);
Console.Write("第三条线段:");
L3.write();
Line L4 = new Line(6, 1, 0, 9);
Console.Write("第四条线段:");
L4.write();
Console.Write("判断两条线段是否相等:");
if (L1 == L2)
Console.WriteLine("L1和L2两条线段相等");
else
Console.WriteLine("L1和L2两条线段不相等");
Console.Write("判断两条线段是否相交:");
if (L3.intersect(L4))
Console.WriteLine("L3和L4两条线段相交");
else
Console.WriteLine("L3和L4两条线段不相交");
}
}
}
输出:
第一条线段:起点(1,2),终点(2,3)
第二条线段:起点(6,7),终点(7,8)
第三条线段:起点(1,2),终点(7,9)
第四条线段:起点(6,1),终点(0,9)
判断两条线段是否相等:L1和L2两条线段相等
判断两条线段是否相交:L3和L4两条线段相交
总结
这次学习了静态成员和非静态成员、常量字段和只读字段、方法参数的值传递和引用传递、构造函数、操作符重载、格式化和解析。编写了Point类和Line类的代码。其中Line类的线段相交判定算法参考了其他博客中提到的方法。