C# 面向对象总结
Demo1: 使用C#查看和启动某进程
首先需要引入头文件:
using System.Diagnostics;
代码如下:
namespace _01进程
{
class Program
{
static void Main(string[] args)
{
Process[] pro = Process.GetProcesses();
foreach(var item in pro)
{
Console.WriteLine(item.ProcessName);
}
// 使用进程打开应用程序
Process.Start("notepad");
Process.Start("mspaint");
Process.Start("chrome", "www.baidu.com");
// 使用进程打开文件
// 首先封装要打开的文件
ProcessStartInfo psi = new ProcessStartInfo(@"C:\Users\CY\Desktop\xxxxx.docx");
// 创建进程对象
Process process = new Process();
process.StartInfo = psi;
process.Start();
}
}
}
Demo2:使用简单的面向对象知识处理进程
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
namespace _02打开文件练习
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("请输入要打开文件的所在路径");
string filePath = Console.ReadLine();
Console.WriteLine("请输入要打开文件的名字");
string fileName = Console.ReadLine();
// 通过简单工厂设计模式返回父类
BaseFile bf = GetFile(filePath, fileName);
if (bf != null)
{
bf.OpenFile();
}
}
static BaseFile GetFile(string filePath, string fileName)
{
BaseFile bf = null;
// 获得文件后缀名
string strExtension = Path.GetExtension(fileName);
switch (strExtension)
{
case ".txt":
bf = new TxtFile(filePath, fileName);
break;
case ".avi":
bf = new AviFile(filePath, fileName);
break;
case ".mp4":
bf = new MP4File(filePath, fileName);
break;
}
return bf;
}
}
// 由于不知道用户所选择的文件类型,因此需要一个表示文件的基类
class BaseFile
{
// 能写在类中的内容:1.字段 2.属性 3.构造函数 4.函数 5.索引器
// 构造函数
public BaseFile(string filePath, string fileName)
{
this.FilePath = filePath;
this.FileName = fileName;
}
private string _filePath;
// 使用ctrl + r + e快捷键,封装字段,生成对应的属性
public string FilePath
{
get
{
return _filePath;
}
set
{
_filePath = value;
}
}
// 自动属性的快捷键:prop+tab+tab
public string FileName { get; set; }
// 设计一个函数,用来打开指定的文件
public void OpenFile()
{
ProcessStartInfo psi = new ProcessStartInfo(this.FilePath + "\\" + this.FileName);
Process pro = new Process();
pro.StartInfo = psi;
pro.Start();
}
}
// TXT文件类
class TxtFile : BaseFile
{
// 由于子类默认调用父类的无参构造函数,而由于父类中实现了构造函数,因此父类中的默认无参构造函数失效
// 这就需要子类重新实现构造函数
// base(filePath, fileName)的作用:显示的调用父类的构造函数
public TxtFile(string filePath, string fileName) : base(filePath, fileName)
{
}
}
// MP4文件类
class MP4File : BaseFile
{
public MP4File(string filePath, string fileName) : base(filePath, fileName)
{
}
}
// AVI文件类
class AviFile : BaseFile
{
public AviFile(string filePath, string fileName) : base(filePath, fileName)
{
}
}
}
Demo3:面向对象练习
namespace _03面向对象练习
{
class Program
{
static void Main(string[] args)
{
}
}
class Person
{
// 字段、属性、函数、构造函数
// 字段:存储数据
// 属性:用于保护字段
// 函数:描述对象的行为
// 构造函数:初始化对象,给对象的每个属性赋值
string _name;
public string Name
{
get
{
return _name;
}
set
{
_name = value;
}
}
int _age;
public int Age
{
get
{
return _age;
}
set
{
_age = value;
}
}
public char Gender { get; set; }
public Person(char gender)
{
if (gender != '男' && gender != '女')
{
gender = '男';
}
this.Gender = gender;
}
}
}
Demo4:三个关键字
C#中的三个关键字:
new
1. 创建对象
---在堆中开辟空间
---在开辟的堆空间中创建对象
---调用对象的构造函数
2. 隐藏父类的成员
this
1. 代表当前类的对象
2. 显式的调用自己的构造函数
base
1. 显式调用父类的构造函数
2. 调用父类的成员
namespace _04三个关键字
{
class Program
{
static void Main(string[] args)
{
}
}
class Person
{
public void SayHello()
{
Console.WriteLine("我是人类");
}
}
class Student : Person
{
// new的作用是显式告诉编译器SayHello已经覆盖了父类的SayHello函数,若不加new会有警告信息
public new void SayHello()
{
Console.WriteLine("我是学生");
}
public Student GetStudent()
{
return this;
}
// base代表父类(不是父类对象)
public void PersonSayHello()
{
base.SayHello();
}
}
class Teacher
{
public string Name { get; set; }
public int Age { get; set; }
public char Gender { get; set; }
public int Chinese { get; set; }
public int Math { get; set; }
public int English { get; set; }
// 构造函数
public Teacher(string name, int age, char gender, int chinese, int math, int english)
{
this.Name = name;
this.Age = age;
this.Gender = gender;
this.Chinese = chinese;
this.Math = math;
this.English = english;
}
// this:显式调用自己的构造函数
public Teacher(string name, int age, char gender):this(name, age, gender, 0, 0, 0)
{
}
public Teacher(string name, int chinese, int math,int english) : this(name, 0, '\0', chinese, math, english)
{
}
}
}
Demo5:多态的实现
面向对象的三大特性:
- 封装:
---减少了大量的冗余代码
---封装功能,对外提供简单的接口 - 继承:
---减少了类中的冗余代码
---让类之间产生了关系,为多态打下基础
继承的特性:
---单根性:一个子类只能有一个父类
---传递性:B继承A,C继承B,C可以访问A
里氏转换:(子类和父类之间可以相互转化,这就是多态的基础)
---子类可以赋值给父类
---如果父类中装的是子类对象,则可以将这个父类转换为对应的子类对象
---关键字
---is:返回bool类型,指示是否可以做这个转化
---as:如果转化成功,则返回对象,否则返回null
作用:我们可以将所有的子类都当作父类来看,针对父类进行编程,写出通用的代码,适应需求的不断改变。 - 多态:
---虚方法
virtual override
---抽象类
abstract override
---接口
interface
namespace _05动物类继承
{
class Program
{
static void Main(string[] args)
{
// 实现多态:声明父类去指向子类对象
Animal[] a = { new Cat(), new Dog() };
for(int i = 0; i < a.Length; i++)
{
a[i].Bark();
a[i].Drink();
a[i].Eat();
}
}
}
abstract class Animal
{
// 抽象成员只能存在于抽象类中
public abstract void Bark();//父类没办法确定子类如何实现,因此不能写具体实现
public void Eat()
{
Console.WriteLine("动物舔着吃");
}
public void Drink()
{
Console.WriteLine("动物舔着喝");
}
}
class Cat : Animal
{
public override void Bark()
{
Console.WriteLine("猫咪喵喵叫");
}
}
class Dog : Animal
{
public override void Bark()
{
Console.WriteLine("狗汪汪叫");
}
}
}
Demo6:里氏转换
namespace _06里氏转换
{
class Program
{
static void Main(string[] args)
{
Person person = new Student();
/*
if (person is Teacher)
{
}
*/
Student student = person as Student;// 将person转化为student对象
if (student != null)
{
student.StudentSayHello();
} else
{
Console.WriteLine("转换失败");
}
}
}
class Person
{
public void PersonSayHello()
{
Console.WriteLine("我是父类");
}
}
class Student : Person
{
public void StudentSayHello()
{
Console.WriteLine("我是学生");
}
}
class Teacher : Person
{
public void TeacherSayHello()
{
Console.WriteLine("我是老师");
}
}
}
Demo7:virtual和override
若不加virtual和override关键字时
namespace _07虚方法
{
class Program
{
static void Main(string[] args)
{
BaseClass baseClass = new BaseClass();
Derived derived = new Derived();
baseClass.PrintMethod();//输出base
derived.PrintMethod();//输出devired
baseClass = new Derived();
baseClass.PrintMethod();//输出base
}
}
class BaseClass
{
public void PrintMethod()
{
Console.WriteLine("base");
}
}
class Derived : BaseClass
{
public void PrintMethod()//此处有警告,因为覆盖了父类的方法,并且没有显式加new关键字
{
Console.WriteLine("derived");
}
}
}
上述没有使用virtual和override的重写实际上起到了隐藏父类方法的作用
2.使用virtual和override的重写
namespace _07虚方法
{
class Program
{
static void Main(string[] args)
{
BaseClass baseClass = new BaseClass();
Derived derived = new Derived();
baseClass.PrintMethod();//输出base
derived.PrintMethod();//输出devired
baseClass = new Derived();
baseClass.PrintMethod();//输出devired
}
}
class BaseClass
{
public virtual void PrintMethod()
{
Console.WriteLine("base");
}
}
class Derived : BaseClass
{
public override void PrintMethod()
{
Console.WriteLine("derived");
}
}
}
解释如下:
BaseClass baseClass = new Derived();
上述语句,BaseClass叫做声名类,Derived叫做实例类
编译器具体的检查流程如下:
1.当调用函数时,系统直接检查声明类,查看所调用函数是否是虚函数
2.如果不是,直接执行该函数。若是virtual函数,转去检查实例类
3.在实例类中,若有override的函数,则执行,若没有,则依次上溯,对父类进行检查,直到找到第一个override了此函数的父类,然后执行
因此,若Derived类中没有override,则在BaseClass中执行同名函数
Demo8:抽象类
抽象类知识点:
- 抽象成员必须标记为abstract,并且不能有具体实现
- 抽象成员必须在抽象类中
- 抽象类不能被实例化
- 子类继承抽象类后,必须把父类中的所有抽象成员重写(若子类也是抽象类,则不用)
- 抽象成员的访问修饰符不能是private
- 抽象类中可以包含实例成员,并且抽象类中的实例成员可以不被子类实现
- 抽象类有构造函数,虽然不能被实例化
- 如果父类的抽象方法中有参数,则继承这个父类的子类在重写父类的方法时必须传入对应参数,返回值同理
若父类中的方法有默认的实现,并且父类需要被实例化,可以考虑将父类定义成一个普通类,用虚方法来实现多态
若父类中的方法没有默认实现,父类也不需要被实例化,则可以定义为抽象类
namespace _08抽象类练习
{
class Program
{
static void Main(string[] args)
{
}
}
// 抽象类
abstract class MobileStorage
{
public abstract void Read();
public abstract void Write();
}
class Phone : MobileStorage
{
public override void Read()
{
Console.WriteLine("手机在读取数据");
}
public override void Write()
{
Console.WriteLine("手机在写入数据");
}
}
class MP3 : MobileStorage
{
public override void Read()
{
Console.WriteLine("MP3在读取数据");
}
public override void Write()
{
Console.WriteLine("MP3在写入数据");
}
public void PlayMusic()
{
Console.WriteLine("MP3在播放音乐");
}
}
class Computer
{
public MobileStorage MS
{
get;
set;
}
public void ComputerRead()
{
this.MS.Read();
}
public void ComputerWrite()
{
this.MS.Write();
}
}
}
Demo9:接口的使用
接口知识点:
- 接口更多的表示一种规范,一种能力,功能要单一
- 一个类继承了一个接口,就必须实现这个接口的所有成员
- 接口不能被实例化
- 接口中的成员不能加访问修饰符,默认为public,不能修改
- 接口中的成员不能有任何实现
- 接口中只能有方法、属性、索引器、事件,不能有字段和构造函数
- 接口之间可以继承
- 实现接口的子类必须实现该接口的所有成员
- 一个类可以同时继承一个类并实现多个接口,如果一个子类同时继承了父类A,并实现了接口IA,则语法上A必须写在IA前面
- 当一个抽象类实现接口时,需要子类去实现接口
namespace _09接口的使用
{
class Program
{
static void Main(string[] args)
{
// 实现多态
IEat[] eaters = { new Student(), new Teacher() };
for (int i = 0; i != eaters.Length; i++)
{
eaters[i].Eat();
}
}
}
class Person
{
public void PersonSayHello()
{
Console.WriteLine("Person:Hello!");
}
}
interface IEat
{
void Eat();
}
class Student : Person, IEat
{
public void Eat()
{
Console.WriteLine("Student:I Can Eat");
}
}
class Teacher: Person, IEat
{
public void Eat()
{
Console.WriteLine("Teacher:I Can Eat too");
}
}
}
Demo10:显示实现接口
namespace _10显示实现接口
{
class Program
{
static void Main(string[] args)
{
}
}
interface I
{
void Test();
}
class Person : I
{
public void Test()
{
Console.WriteLine("这个Test函数是属于Person的");
}
void I.Test()
{
Console.WriteLine("显示实现接口的Test函数");
}
}
}