关于父类引用指向子类对象c#
例如: 有如下2个类ide
public class Father { public int age = 70; public static string name = "父亲"; } public class Son : Father { public int age = 30; public static string name = "儿子"; }
Father f=new Son(); 函数
这种用法叫作“父类引用指向子类对象,或者叫“父类指针指向子类对象”,指的是定义一个父类的引用,而它实际指向的是子类建立的对象。测试
好处是什么?spa
下面作几个测试, 指针
第一种 ,父类变量,调用 属性 例以下面的 f.age 是一个父类的变量调用了属性,问题是这里的属性是父类的?仍是子类的? 答案是父类的属性code
class Program { static void Main(string[] args) { Father f=new Son(); Console.WriteLine(f.age); //这里输出的是父类的年龄?仍是子类的年龄? 答案是父亲的年龄 70 ,由于这里的f是个父类类型,因此是调用父类的属性 Son s = f as Son; Console.WriteLine(s.age); //这里输出的父类的年龄?仍是子类的年龄? 答案是子类的年龄 30 Console.ReadKey(); } public class Father { public int age = 70; //第4执行 public static string name = "父亲"; //第3执行 } public class Son : Father { public int age = 30; //第2执行 public static string name = "儿子"; //第1执行 } }
小结论(1): 当用父类的变量调用属性的时候,取决于声明的类型(“=”左边是什么类型),而不是后面实例化的类型orm
第二种 ,父类变量,调用 方法 (父类的方法和子类的方法 如出一辙,子类并没有重写) 对象
public class Father { public int age = 70; //第4执行 public static string name = "父亲"; //第3执行 public void SayHi() { Console.WriteLine(string.Format("父亲说,年龄{0},名字是{1}",age,name)); } } public class Son : Father { public int age = 30; //第2执行 public static string name = "儿子"; //第1执行 public void SayHi() { Console.WriteLine(string.Format("儿子说,年龄{0},名字是{1}", age, name)); } }
static void Main(string[] args) { Father f = new Son(); f.SayHi(); //这里调用的是父类的方法,由于f是父类,而且子类,压根就没有重写 父亲说,年龄是70,名字是父亲 Son s = f as Son; s.SayHi(); //这里调用的是父类的方法?仍是子类的方法? 答案是子类的方法,由于s是子类 儿子说,年龄是30,名字是儿子 Console.ReadKey(); }
小结论(2): 当子类和父类的方法彻底相同时,调用的时候取决于声明的类型(“=”左边),而不是后面实例化的类型。blog
第三种 ,父类变量,调用 方法 (父类的方法和子类的方法 如出一辙 ,可是父类的方法加 Virtual , 子类不重写)
小结论(3):若是父类有virtual虚方法,可是子类并无重写的话,那么 同上面的小结论(2)同样,调用的时候,取决于声明的类型(“=”的左边),而不是实例化的类型
第四种 ,父类变量,调用 方法 (父类的方法和子类的方法 如出一辙 ,可是父类的方法加 Virtual , 子类重写)
小结论(4):重写之后,调用哪一个类的方法取决于实例化的类型(“=”右边)或者是转换后最终的类型
第五种 ,父类变量,调用 方法 (父类的方法和子类的方法 如出一辙 ,可是父类的方法加 Virtual , 子类重写)
父类变量指向子类的实例,可是咱们直接调用父类变量下的属性,会输出子类的属性?仍是父类的属性?答案是父类的属性.
那若是再继续调用方法的话,是调用父类的方法?仍是子类的方法?答案是,若是是虚方法,子类有重写,就调用子类的,子类没有重写,就调用父类的.
小结论(5) : 若是子类方法里面想调用父类的属性或者是方法,使用 base 关键字
结论:
1:当用父类的变量调用属性的时候,取决于声明的类型(“=”左边是什么类型),而不是后面实例化的类型
例如 输出 f.age 就是输出父类的属性 ,而不是子类的属性
2:当子类和父类的方法彻底相同时,调用的时候取决于声明的类型(“=”左边),而不是后面实例化的类型。
也就是子类没有重写的时候. f.sayhi 就是调用的父类的sayhi ,而不是子类的sayhi
3 若是子类有重写(override)父类的方法,那么 父类变量调用方法的时候,就变成使用 子类的方法.
也就是子类有override的时候,f.sayhi 就是调用子类的sayhi
4:若是想在子类里面访问父类的属性或者是方法,使用 base 关键字
C#中new和override的区别;abstract
当父类里面有 virtual 方法的时候,子类可使用 override 进行重写. 那么 f.sayhi 就变成调用子类的sayhi
不论父类的方法有没有virtual,子类均可以在同名的方法上加一个new表示这是子类本身的方法,那么父类的方法就会被隐藏起来, f.sayhi 就会变成 调用父类的sayhi,由于子类并无override. 若是这个时候,把new去掉,效果也是同样的,f.sayhi 也是调用父类的sayhi, 判断是否调用子类的方法,就看子类是否有override重写.
//在C#中,override和new都会覆盖父类中的方法。那它们二者以前有什么区别呢? //override是指“覆盖”,是指子类覆盖了父类的方法。子类的对象没法再访问父类中的该方法(固然了,在子类的方法中仍是能够经过base访问到父类的方法的)。
//new是指“隐藏”,是指子类隐藏了父类的方法,固然,经过必定的转换,能够在子类的对象中访问父类的方法。
c#类的初始化顺序
子类的静态成员变量,子类的普通成员,父类的静态成员,父类的普通成员
namespace 类的初始化顺序 { class Program { static void Main(string[] args) { Father f=new Son(); Console.ReadKey(); } public class Father { public int age = 70; //第4执行 public static string name = "父亲"; //第3执行 } public class Son : Father { public int age = 30; //第2执行 public static string name = "儿子"; //第1执行 } } }
首次访问:(在此没有显示的写出类中的构造方法) 顺序:子类的静态字段==》子类静态构造==》子类非静态字段==》父类的静态字段==》父类的静态构造==》父类的非静态字段 ==》父类的构造函数==》子类的构造函数 非首次访问:顺序是同样的,只不过少了中间静态字段和构造的过程 对于静态变量与静态构造函数而言, 不管对一个类建立多少个实例,它的静态成员都只有一个副本。 也就是说,静态变量与静态构造函数只初始化一次(在类第一次实例化时)