本文主要用于供自身复习使用,上篇文章首先回顾了C#中的数据类型,数据转换以及数据之间进行运算的运算符,然后回顾了基本的流程控制语句if else,switch for,while等,最后还回顾了数组,枚举,结构体,类,接口,抽象类等基本的数据结构,本文将从面向对象编程的角度进一步的回顾相关知识。
把现实世界中的对象使用代码的形式表现出来
题外话:面向对象的编程,那么什么是对象呢?一般都会说,一切事物都是对象,但是这种答案是对也不对!
找到一个相对具体的说法是这样的:编程的本质呢?其实大部分都在与数据打交道,不是在存储数据,就是围绕数据做延申的功能,那么可以这么理解对象,对象就像是个“盒子容器”,用来存放数据和功能, 也就是数据和功能的集合。
变量封装到类中,分为两种形式:
字段:变量的声明,使用_标识
属性:使用get 和set 进行包装,一般首字母大写,符合驼峰命名规则
代码如下(示例):
class UserInfo
{
private string _id;
public string Id
{
get { return _id; }
set { _id = value; }
}
}
关于get 和set 的理解如下:
private int _id;
public int Id
{
get//返回给外界的值,供外界调用读取的值
{
if (_id < 0)//如果内部逻辑得出的_id<0,则同一返回0
{
_id = 0;
}
return _id;
}
set//供给外界设置的窗口,如果设置为private,外界将无法为该属性赋值,为只读属性
{
if (value>999)//value 即是外界赋予的值,可以通过set来处理外界的值
{
_id = 999;//如果外界赋予的值大于999,则统一修正为999
}
_id = value;
}
}
继承的可扩展性体现在:继承的时候,子类不仅沿用父类中非私有的属性和行为,还可增加自己特有的内容,另外通过重写和重载,同样实现了内容的扩展
注意 : 继承的时候,一个类只能有一个父类
继承我们通过冒号(:)表示,表现形式如下:
class Shape
{
public void setWidth(int w)
{
width = w;
}
public void setHeight(int h)
{
height = h;
}
protected int width;
protected int height;
}
// 派生类
class Rectangle: Shape
{
//通过 Rectangle: Shape 的形式表示:Rectangle继承自Shape
//由于Rectangle继承自Shape,就有了Shape中非私有的width和height变量以及setWidth和setHeight
public int getArea()
{
return (width * height);
}
}
class RectangleTester
{
static void Main(string[] args)
{
Rectangle Rect = new Rectangle();
Rect.setWidth(5);
Rect.setHeight(7);
// 打印对象的面积
Console.WriteLine("总面积: {0}", Rect.getArea());
Console.ReadKey();
}
}
重写:在子类中重新编写父类方法
重写具有相同的方法名、参数列表以及返回值
重写的方式有如下两种:
class Animal
{
public void Eat()
{
Console.WriteLine("吃");
}
//定义虚方法,需子类重新,另外abstract 自带virtual属性
public virtual void Action()
{
Console.WriteLine("行动");
}
}
class Monkey:Animal
{
//通过new 重写父类的方法
public new void Eat()
{
Console.WriteLine("猴子吃香蕉");
}
//通过override重写
public override void Action()
{
base.Action();//重写后,可以通过base调出父类的原方法执行,也可不调用,重新实现
Console.WriteLine("猴子上树");
}
}
重载:就是在同一个类中有多个同名方法,但是方法的参数列表不同
重载可以实现一种方法的多种实现方式,有利于程序的扩展。
class Animal
{
public void Eat()
{
Console.WriteLine("吃");
}
public void Eat(string food)
{
Console.WriteLine($"吃{food}");
}
public void Eat(int num,string food)
{
Console.WriteLine($"一天吃{num}次{food}");
}
public int Eat(string name ,int num,string food)
{
Console.WriteLine($"{name}一天吃{num}次{food}");
//如猴子一天吃三次香蕉,(假如一次2根),返回一天总量
return num * 2 ;
}
}
静态多态性通过函数(方法)重载和运算符重载实现。
函数重载上面已经介绍了,这里介绍以下运算符的重载。
C# 允许用户定义的类型通过使用 operator 关键字定义静态成员函数来重载运算符。
注意必须用public修饰且必须是类的静态的方法。
运算符的重载可为用户自定义的对象实现运算。
运算符重载的使用案例如下:
class Rect
{
public double Width { get; set; }
public double Length { get; set; }
public static Rect operator+(Rect a,Rect b)
{
Rect rect = new Rect();
rect.Width = a.Width + b.Width;
rect.Length = a.Length + b.Length;
return rect;
}
public double GetArea()
{
return Width * Length;
}
}
class Program
{
static void Main(string[] args)
{
Rect RectA = new Rect() { Width=2.5,Length=4};
Rect RectB = new Rect() { Width=3.5,Length=6};
Console.WriteLine($"RectA的面积{RectA.GetArea()}");
Console.WriteLine($"RectB的面积{RectB.GetArea()}");
//如果没有通过operator+ 进行重载,RecA是无法和RecB进行相加的操作的
Rect RectC = RectA+RectB;
Console.WriteLine($"RectC的面积{RectC.GetArea()}");
Console.ReadLine();
}
}
下图罗列了可重载和不可重载的运算符
这里解释以下成对重载,也就是说,如果我们重载了==,那么就必须连同 != 一起重载
详细使用如下:
class Program
{
static void Main(string[] args)
{
Student student = new Student(15, "小栗子");
var student1 = student + 3;
var student2 = student + "新手小白";
Console.WriteLine(student1.ToString());//年龄 = 18,名称 = 小栗子
Console.WriteLine(student2.ToString());//年龄 = 15,名称 = 新手小白小栗子
Student stu1 = new Student(12, "小张子");
Student stu2 = new Student(18, "小王五");
var stu3 = stu1 - stu2;
Console.WriteLine(stu3.ToString()); //年龄 = 6,名称 = 小张子和小王五
Console.ReadLine();
}
}
public class Student
{
public int Age { get; set; }
public string Name { get; set; }
public Student()
{ }
public Student(int age, string name)
{
this.Age = age;
this.Name = name;
}
# 形如 public static Student operator +(int c1, int c2) 是会报错的
# 因为这样,就与需要操作的Student类毫无关联!
# 二元运算符的参数之一必须是包含类型(参数c1、c2中有一个类型为Student即可).
//+重载 ,操作年龄
public static Student operator +(Student stu, int c2)
{
return new Student(stu.Age + c2, stu.Name);
}
//+重载 ,增加姓名前缀
public static Student operator +(Student stu, string prefix)
{
return new Student(stu.Age, prefix+stu.Name);
}
//重载运算符"-",计算两个学生的年龄差.
public static Student operator -(Student a, Student b)
{
return new Student(Math.Abs(a.Age - b.Age), $"{a.Name}和{b.Name}");
}
//重写ToString方法,格式化输出
public override string ToString()
{
return $"年龄={Age},名称={Name}";
}
}
动态多态性是通过 抽象类、接口 和 虚方法 实现的。
abstract class Animal
{
public abstract void Run();//abstract 自带virtual属性
}
interface IFly//接口默认public,通常接口命名以 I 开头
{
void Fly();//飞翔这项功能作为一个接口,并不是所有动物都可以的
}
class Monkey : Animal
{
public override void Run()
{
Console.WriteLine("猴子在奔跑!");
}
}
class Pig : Animal
{
public override void Run()
{
Console.WriteLine("小猪在狂奔!");
}
}
//同一个方法(“接口”)Run,在不同的实例中有不同的实现就是多态的一种体现
# 这里需要注意:当一个子类同时继承抽象类,类,和接口的时候,抽象类,类必须排在接口前面
class Brid : Animal, IFly
{
public void Fly()
{
Console.WriteLine("奋飞的小鸟!");
}
public override void Run()
{
Console.WriteLine("愤怒的小鸡在奔跑!");
}
}
class Worker
{
public virtual void DoWork()
{
Console.WriteLine("做工作!");
}
}
class WorkerA : Worker
{
public override void DoWork()
{
base.DoWork();
Console.WriteLine("编写项目ppt");
}
}
class Worker
{
public virtual void DoWork()
{
Console.WriteLine("做工作!");
}
}
class WorkerA : Worker
{
public override void DoWork()
{
base.DoWork();
Console.WriteLine("编写项目ppt");
}
public void Avocation()
{
Console.WriteLine("WorkA的业余爱好");
}
}
class Program
{
static void Main(string[] args)
{
//向上转型
Worker worker= new WorkerA();
worker.DoWork();
/* 输出:
做工作!
编写项目ppt
*/
//worker.Avocation();
//注意这里会报错:因为上转型变量是不可调用 子类中扩展的方法的,只能调用两者共有的方法
//向下转型
//这种情况是不合理的,因为相当于用父类替换子类,然而子类会有扩展,不可能完全替换
//Worker wo = new Worker();
//WorkerA wa = (WorkerA)wo;
Worker wo = new WorkerA();
WorkerA wa = (WorkerA)wo;
wa.Avocation();//这样是可行的,因为自始至终实例都是WorkA
wo.DoWork();
/*
WorkA的业余爱好
做工作!
编写项目ppt
*/
Console.ReadLine();
}
}
以上就是本文的内容,希望以上内容可以帮助到您,如文中有不对之处,还请批评指正。
参考资料:
C# 运算符重载
菜鸟教程-C# 运算符重载