1.1派生
继承是为了扩展现有类型来添加更多功能来设计的。
派生类继承了除了构造器和析构器(析构主要是用来释放运行时暂用的内存的,在C#中一般很少用,一般用垃圾回收器自动释放的!)之外的所有基类成员
1.1.2private访问修饰符
派生类不能访问基类的私有成员,
1.1.3protected访问修饰符
基类中的受保护的 成员只能从基类以及其派生链中的其他类中访问。
比如;
public class Program
{
static void Main(string[] args)
{
B T = new B();
T.id//这时候报错,Program没有继承A,所以报错。
}
}
public class A
{
protected int id { get; set; }
}
public class B : A
{
public void save()
{
int test = id;
}
}
1.2virtual修饰符
(https://www.cnblogs.com/green-jcx/p/9023141.html 具体的属性和字段的区别的可以参考这个文章)
c#支持重写实例方法和属性,但是不支持重写字段或者任何静态成员。为了进行重写,要求在基类和派生类中都显示执行一个操作。在基类中,必须将允许重写的每个成员标记成virtual(java中默认的都是虚方法,但是c#中磨人的是非虚方法)。假如一个public和protected成员没有包含virtual修饰符,就不允许重写。c#不允许隐式重写,java可以。
eg:
public class Program { public virtual string Name { get; set; } } public class Test : Program { public string FirstName { get; set; } public string LastName { get; set; } public override string Name { get { return LastName + LastName; } set { string[] v = value.Split(','); LastName = v[0]; FirstName = v[1]; } } }
如上述代码:“运行时”遇到虚方法的时候,他会调用虚成员派生的最远的,重写的实现。所以在调用Program类中的 Name属性的时候执行的是重写的代码。所以虚方法不应该包含关键代码,否则会导致原始代码永远得不到调用。只有实例成员(包括实例数据和实例方法 ,必须通过对象来调用,不能使用类名调用。)才可以是virtual的。
1.3new修饰符
eg:
public class Program { public void Display() { Console.WriteLine("Program"); } public static void Main() { Test2 t2 = new Test2(); Program p = t2; Test t = t2; Test1 t1 = t2; t2.Display(); p.Display(); t.Display(); t1.Display(); Console.ReadLine(); // Console.WriteLine("t"); } } public class Test : Program { //可以被重写 public virtual void Display() { Console.WriteLine("Test"); } } public class Test1 : Test { public override void Display() { Console.WriteLine("Test1"); } } public class Test2 : Test1 { public new void Display() { Console.WriteLine("Test2"); } }
上述代码的结果为下:
Test2
Program
Test1
Test1
因为调用重写的方法的时候,找的是派生的最远的方法,但是使用new修饰符之后正好相反,它隐藏了派生类,找的是基类中的方法,Test2的基类是Test1,所以输出是Test1。
1.4sealed修饰符
一般很少将整个类都密封,可以密封单独虚成员,也可以密封整个类,但是需要注意的是被密封的类或者虚成员必须是继承类,不能是基类,
public class Program { public virtual void Display() { Console.WriteLine("Program"); } } public class Test : Program { //这个方法不会被继承Test类的派生类重写了 public override sealed void Display() { Console.WriteLine("Test"); } }
1.5base关键字
public class Program { public Program() { Console.WriteLine("Program构造函数"); } public virtual void Display() { Console.WriteLine("Program"); } public static void Main() { // Test2 t2 = new Test2(); // Program p = t2; Test t = new Test(); t.Display(); // Test1 t1 = t2; // t2.Display(); // p.Display(); // t.Display(); // t1.Display(); Console.ReadLine(); // Console.WriteLine("t"); } } public class Test : Program { public Test():base() { Console.WriteLine("Test构造函数"); } //可以被重写 public override void Display() { Console.WriteLine("Test"); }
结果是:
Program构造函数
Test构造函数
Test
所以使用base()继承基类的构造方法,会同时执行派生类和基类的构造方法。
下面代码是继承
public class Program
{
public void N()
{
Console.WriteLine("N");
}
public virtual void Display()
{
Console.WriteLine("Program");
}
public static void Main()
{
// Test2 t2 = new Test2();
// Program p = t2;
Test t = new Test();
t.Display();
// Test1 t1 = t2;
// t2.Display();
// p.Display();
// t.Display();
// t1.Display();
Console.ReadLine();
// Console.WriteLine("t");
}
}
public class Test : Program
{
//可以被重写
public override void Display()
{
base.N();
base.Display();
Console.WriteLine("Test");
}
}
结果:
N
Program
Test
base 关键字用于从派生类中访问基类的成员:
调用基类上已被其他方法重写的方法。
指定创建派生类实例时应调用的基类构造函数。
基类访问只能在构造函数、实例方法或实例属性访问器中进行。