一、类(class)
1、定义一个类中包含
- 成员变量,也称作字段
- 成员函数,也称作方法
【注意】:在同一个命名空间下定义的类时,相互调用时不需要引入命名空间。若是在不同的命名空间下,则在使用之前需要引入命名空间。
在一个类中调用另一个类中的变量或函数时,需要先为被调用的类创建对象,并将该对象初始化。然后再通过该对象来调用对应的变量或函数。
// 自定义的类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CZBKe
{
class MyClass
{
public string name;
public int age;
public void Show()
{
Console.WriteLine("Just a test");
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CZBKe
{
class Program
{
static void Main(string[] args)
{
// 创建类的对象,并用 new 进行初始化
MyClass myst = new MyClass();
myst.age = 20;
myst.Show();
Console.ReadKey();
}
}
}
2、类的构造函数
// 自定义的类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TheUseClass
{
class NewCreateClass
{
// 一般将数据成员(即字段)设置为私有
private float x, y, z;
// 为字段提供方法来设置字段的值
public void SetX(float x)
{
// 通过this 表示访问的是类的字段或方法
this.x = x;
}
public void SetY(float y)
{
this.y = y;
}
public void SetZ(float z)
{
this.z = z;
}
public float Dis()
{
return (float)Math.Sqrt(x * x + y * y + z * z);
}
}
class VectorTest
{
private float x, y, z;
public VectorTest(float x,float y,float z) // 构造函数
{
this.x = x;
this.y = y;
this.z = z;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TheUseClass
{
class Program
{
static void Main(string[] args)
{
NewCreateClass myclass = new NewCreateClass();
// 通过公有的函数来设置字段的值
myclass.SetX(10);
myclass.SetY(20);
myclass.SetZ(30);
Console.WriteLine(myclass.Dis());
// 调用构造函数
VectorTest vt = new VectorTest(1,2,3);
Console.ReadKey();
}
}
}
二、继承
继承有两种:实现继承、接口继承。【注】 C# 不支持实现多重继承
1、两种继承的定义
实现继承: 表示一个类型派生于一个基类型,它拥有该基类型的所有成员字段和函数。在实现继承中,派生类型采用基类型的每个函数的实现代码,除非在派生类型的定义中指定重写某个函数的实现代码。在需要给现有的类型添加功能,或许多相关的类型共享一组重要的公共功能时,这种类型的继承非常有用。
接口继承:表示一个类型只是继承了函数的签名,没有继承任何代码。在需要指定该类型具有某些可用的特性时,最好使用这种类型的继承。
(1)实现继承:继承父类的子类
// 基类
using System;
namespace ATotal
{
class BaseClass
{
public float Speed { get; set; }
public float Move { get; set; }
public string Area { get; set; }
public void AI()
{
Console.WriteLine("调用基类 AI");
}
}
}
// 继承基类的子类
using System;
namespace ATotal
{
class DeriveClass:BaseClass
{
public void Test()
{
Console.WriteLine("This is derive class");
}
}
}
// 主函数所在的类
using System;
namespace ATotal
{
class Program
{
static void Main(string[] args)
{
DeriveClass deriveClass = new DeriveClass();
deriveClass.AI();
deriveClass.Test();
Console.ReadKey();
}
}
}
(2)、父类声明的对象可以使用子类去构造;但是子类声明的对象不可以使用父类去构造。因为子类比父类范围更大。
BaseClass theBase; // 父类声明的对象
theBase = new DeriveClass(); // 用子类来进行构造
(3)、一个对象是什么类型的,主要是看它通过什么构造的,如:
BaseClass theBase = new BaseClass();
DeriveClass derive = (DeriveClass)theBase;
2、派生类的构造函数
(1)、在子类中掉用父类的无参构造函数。
【注】 此时可以省略掉 : base ()
// 基类
using System;
namespace ATotal
{
class BaseClass
{
public BaseClass()
{
Console.WriteLine("This is Base Class");
}
}
}
// 派生类
using System;
namespace ATotal
{
class DeriveClass:BaseClass
{
// 会先默认调用父类中的无参构造函数,再调用子类中的构造函数
public DeriveClass():base()
{
Console.WriteLine("This is Derive class");
}
}
}
//主函数的类
using System;
namespace ATotal
{
class Program
{
static void Main(string[] args)
{
// 在此会默认调用主函数中的无参构造函数
DeriveClass derive1 = new DeriveClass();
Console.ReadKey();
}
}
}
(2)、调用基类有参的构造函数
// 基类
using System;
namespace ATotal
{
class BaseClass
{
private float x;
public BaseClass(float x)
{
this.x = x;
Console.WriteLine("This is Base Class. x = "+this.x);
}
}
}
// 派生类
using System;
namespace ATotal
{
class DeriveClass:BaseClass
{
private float y;
public DeriveClass(float x ,float y):base( x)
{
this.y = y;
Console.WriteLine("This is Derive class y = "+this.y);
}
}
}
// 主函数所在类
using System;
namespace ATotal
{
class Program
{
static void Main(string[] args)
{
// 在此会默认调用主函数中的无参构造函数
DeriveClass derive1 = new DeriveClass(10,20);
Console.ReadKey();
}
}
}
运行结果如下所示
三、虚函数、base、this 关键字
1、有 virtual 关键字修饰的函数,表示该方法可以被继承的类重写。
2、有 override 关键字修饰时,表示重写了一个父类的方法。
public class Student
{
public virtual void MyFunc() //virtual:该方法可以被继承的类重写
{
Console.WriteLine(1);
}
}
public class MyStudent:Student
{
public override void MyFunc() //override:重写了一个父类的方法。
{
Console.WriteLine(2);
}
}
【注】:对于子类继承父类,并重写父类中的虚方法。父类创建的对象会调用父类中的方法,子类创建的对象会调用子类中的方法。
3、如果父类和派生类中都声明了同一个方法,但该方法在父类中没有用 virtual 关键字,在子类中没有用 override 关键字,则派生类就会隐藏基类中的该方法。如果用子类声明的对象,则会调用子类中的该方法;如果使用父类声明的对象,则会调用父类中的该方法。
4、base 与 this 关键字。当父类与子类具有相同的成员时,通过base关键字来调用父类的成员;通过 this 关键字来调用当前类的成员(有没有this都可以访问)。如下所示。
public class Student{
public virtual void MyFunc(){
Console.WriteLine(1);
}
}
public class MyStudent:Student{
public override void MyFunc(){
Console.WriteLine(2);
}
// 通过base关键字调用父类的函数成员。
public void f1(){
base.MyFunc();
}
// 通过this关键字调用子类的函数成员。
public void f2(){
this.MyFunc();
}
}
【注】:当方法的参数跟字段重名时,使用this 可以表明访问的是类中的字段。
class Test02
{
private float x;
public Test02(float x)
{
this.x = x;
}
}
四、抽象类
1、定义
2、当子类一定会去重写父类的方法时,可以将父类中的方法定义为抽象类。如果一个类中包含有抽象函数,则该类一定是抽象类。因为抽象类是不完整的,所以抽象类不能用于构造函数对象。
// 抽象的基类
using System;
namespace ATotal
{
abstract class BaseClass
{
private float speed;
public void Eat()
{
}
abstract public void Fly();
}
}
// 继承抽象类的一个子类
using System;
namespace ATotal
{
class DeriveClass:BaseClass
{ // 继承一个抽象类的时候必须要去实现抽象方法,因为父类未进行实现
public override void Fly()
{
Console.WriteLine("This is a class derived from a abstract base class");
}
}
}
using System;
namespace ATotal
{
class Program
{
static void Main(string[] args)
{
DeriveClass derive1 = new DeriveClass();
derive1.Fly();
Console.ReadKey();
}
}
}
五、密封类
密封类与密封方法
- 密封类可以用于任何类,将 sealed 放在类前表示该类为密封类,不能被继承。
- 密封方法只能用于重写的方法上(override 修饰的方法上),表示该方法不能再被重写了。
// 密封类
sealed class MyClass
{
}
// 密封方法
// 父类中的方法
public virtual void Eat()
{
}
// 子类中的方法
sealed public override void Eat()
{
}