继承类型分为两种: 实现继承和接口继承。
多重继承: 一个类派生自多个类。
C# 不支持多重实现继承,但允许多重接口继承。
结构不支持继承: 结构不支持实现继承,但是可以支持接口继承。
基类访问
class SomeClass
{
public string Field1 = "Field1 -- In the base class";
}
class OtherClass : SomeClass
{
new public string Field1 = "Field1 -- In the derived class";
public void PrintField1()
{
Console.WriteLine(Field1); // 访问派生类
Console.WriteLine(base.Field1); //访问基类
}
}
class Program
{
static void Main(string[] args)
{
OtherClass oc = new OtherClass();
oc.PrintField1();
Console.ReadKey();
}
}
使用基类的引用
class MyBaseClass
{
public void Print()
{
Console.WriteLine("This is the base class.");
}
}
class MyDerivedClass : MyBaseClass
{
public int var1;
new public void Print()
{
Console.WriteLine("This is the derived class.");
}
}
class Program
{
static void Main(string[] args)
{
MyDerivedClass derived = new MyDerivedClass();
MyBaseClass mybc = (MyBaseClass)derived;
derived.Print();
mybc.Print();
Console.ReadKey();
}
}
输出结果:
Field1 – In the derived class
Field1 – In the base class
把一个基类函数声明为 virtual,就可以在任何派生类中重写该函数。
class MyBaseClass
{
//虚方法
public virtual string VirualMethod()
{
return "This method is virtual and defined in MyBaseClass";
}
//虚属性
public virtual string ForeName
{
get { return foreName; }
set { foreName = value; }
}
private string foreName;
}
class MyDerivedClass : MyBaseClass
{
//使用 override 来 重写虚方法
public override string VirualMethod()
{
return "This method is an override define in MyDerivedClass";
}
}
class Program
{
static void Main(string[] args)
{
MyDerivedClass derived = new MyDerivedClass();
MyBaseClass mybc = (MyBaseClass)derived;
Console.WriteLine(derived.VirualMethod());
Console.WriteLine(mybc.VirualMethod());
Console.ReadKey();
}
}
输出结果:
This method is an override define in MyDerivedClass
This method is an override define in MyDerivedClass
从结果可知,派生类转换为基类,其结果仍是调用派生类重写的虚方法。
若派生类在基类的基础上,对虚方法进行代码逻辑的补充时:
class CustomerAccount
{
public virtual decimal CalculatePrice()
{
return 0.0M;
}
class GoldAccount : CustomerAccount
{
public override decimal CalculatePrice()
{
return base.CalculatePrice() * 90;
}
}
}
如果在基类和派生类中,有签名相同的方法,但该方法没有分别声明为 virrual 和 override,派生类方法就会隐藏基类方法。
隐藏方法存在安全隐患: 由于派生类和基类使用的是相同签名的方法,但该方法执行的结果不相同。若程序员想要调用派生类的,但不小心调用的是基类的,该方法执行后会出现潜在程序的错误。
abstract class Building
{
public abstract decimal CalculateHeatingCost();// abstract method
}
C# 允许把类和方法声明为 sealead。对于类,这表示不能继承该类;对于方法(属性也可密封),这表示不能重写该方法。(密封方法,是否可以使得隐藏方法更加安全)
sealed class FinalClass
{
}
//提示错误,密封类不能被继承
class DerivedClass : FinalClass
{
}
class MyBaseClass1
{
public virtual void TestFun()
{
}
}
class FinalClass : MyBaseClass1
{
sealed public override void TestFun()
{
}
}
class DerivedClass : FinalClass
{
//提示错误,密封方法不能被重写
//因为继承的这个基类设置该方法为密封方法
public override void TestFun()
{
}
}
表-修饰符的访问说明
修饰符 | 应用于 | 说明 |
---|---|---|
public | 所有类或成员 | 任何代码均可以访问该项 |
protected | 类型和内联类型的所有成员 | 只有派生的类型能访问该项 |
internal | 所有类型或成员 | 只能在包含它的程序集中访问该项 |
private | 类型和内联类型的所有成员 | 只能在它所属的类型中访问该项 |
protected internal | 类型和内联类型的所有成员 | 只能在包含它的程序集和派生类型的任何代码中访问该项 |
内嵌类型: 在类的内部再声明一个类
public class OtherClass
{
private int id = 0;
protected class InnerClass
{
public void InnerClassFun()
{
OtherClass oc = new OtherClass();
oc.id = 0;//可访问
}
}
}
表-成员可访问性总结(出自《C# 图解教程》-8.9.7 成员访问修饰符小结)
同一程序集内的类 | 同一程序集内的类 | 不同一程序集内的类 | 不同一程序集内的类 | |
---|---|---|---|---|
非派生类 | 派生类 | 非派生类 | 派生类 | |
private | ||||
internal | ✅ | ✅ | ||
protected | ✅ | ✅ | ||
protected internal | ✅ | ✅ | ✅ | |
public | ✅ | ✅ | ✅ | ✅ |
其他修饰符
修饰符 | 应用于 | 说明 |
---|---|---|
new | 函数成员 | 成员用相同的签名隐藏继承的成员 |
staitc | 所有成员 | 成员不作用于类的具体实例 |
virtual | 仅函数成员 | 成员可以由派生类重写 |
abstract | 仅函数成员 | 虚拟成员定义了成员的签名,但没有提供实现代码 |
override | 仅函数成员 | 成员重写了继承的虚拟或抽象成员 |
sealed | 类、方法和属性 | 对于类,不能继承自密封类。对于属性和方法,成员重写已继承的虚拟成员,但任何派生类中的任何成员都不能重写该成员。该修饰符必须与 override 一起使用 |
extern | 仅静态(DllImport)方法 | 成员在外部用另一种语言实现 |
C# 允许从一个在不同的程序集内定义的基类来派生类。
要从不同程序集中定义的基类派生类,必须具备以下条件: