using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;namespace ConsoleApplication1
{
class A
{
public virtual void F() { Console.WriteLine("A.F"); }
}
class B : A
{
public override void F() { Console.WriteLine("B.F"); }
}
class C : B
{
new public virtual void F() { Console.WriteLine("C.F"); }
}
class D : C
{
public override void F() { Console.WriteLine("D.F"); }
}
class Test
{
static void Main()
{
D d = new D();
A a = d;
B b = d;
C c = d;
a.F();
b.F();
c.F();
d.F();
Console.ReadKey();
}
}
}
using System.Collections.Generic;
using System.Linq;
using System.Text;namespace ConsoleApplication1
{
class A
{
public virtual void F() { Console.WriteLine("A.F"); }
}
class B : A
{
public override void F() { Console.WriteLine("B.F"); }
}
class C : B
{
new public virtual void F() { Console.WriteLine("C.F"); }
}
class D : C
{
public override void F() { Console.WriteLine("D.F"); }
}
class Test
{
static void Main()
{
D d = new D();
A a = d;
B b = d;
C c = d;
a.F();
b.F();
c.F();
d.F();
Console.ReadKey();
}
}
}
using System.Collections.Generic;
using System.Linq;
using System.Text;namespace ConsoleApplication1
{
public abstract class Animal
{
public abstract void ShowType();
public void Eat()
{
Console.WriteLine("Animal always eat.");
}
} public class Bird : Animal
{
private string type = "Bird";
public override void ShowType() { Console.WriteLine("Type is {0}", type); }
private string color;
public string Color { get { return color; } set { color = value; } }
public string Type { get { return type; } set { type = value; } }
} public class Chicken : Bird
{
private string type = "Chicken";
public string Type { get { return type; } set { type = value; } }
public override void ShowType()
{
Console.WriteLine("Type is {0}", type);
}
public void ShowColor() { Console.WriteLine("Color is {0}", Color); }
} public class TestInheritance
{
public static void Main()
{
//Bird bird = new Bird();
//bird.ShowType();
//Chicken chicken = new Chicken();
//chicken.ShowType(); Bird bird2 = new Chicken(); //这种情况下,bird2.ShowType应该返回什么值呢?而bird2.type又该是什么值呢?
//关注对象原则:调用子类还是父类的方法,取决于创建的对象是子类对象还是父类对象,而不是它的引用类型。
//例如Bird bird2 = new Chicken()时,我们关注的是其创建对象为Chicken类型,
//因此子类将继承父类的字段和方法,或者覆写父类的虚方法,而不用关注bird2的引用类型是否为Bird。
//引用类型的区别决定了不同的对象在方法表中不同的访问权限。
//根据关注对象原则,下面的两种情况又该如何区别呢?
//Bird bird2 = new Chicken(); Chicken chicken = new Chicken();
//根据上文的分析,bird2对象和chicken对象在内存布局上是一样的,
//差别就在于其引用指针的类型不同:bird2为Bird类型指针,而chicken为Chicken类型指针。
//以方法调用为例,不同的类型指针在虚拟方法表中有不同的附加信息作为标志来区别其访问的地址区域,称为offset。
//不同类型的指针只能在其特定地址区域内执行,子类覆盖父类时会保证其访问地址区域的一致性,从而解决了不同的类型访问具有不同的访问权限问题。
//— 执行就近原则:对于同名字段或者方法,编译器是按照其顺序查找来引用的,也就是首先访问离它创建最近的字段或者方法,
//例如上例中的bird2,是Bird类型,因此会首先访问Bird_type(注意编译器是不会重新命名的,在此是为区分起见),
//如果type类型设为public,则在此将返回“Bird”值。这也就是为什么在对象创建时必须将字段按顺序排列,而父类要先于子类编译的原因了。
//1.上面我们分析到bird2.type的值是“Bird”,那么bird2.ShowType()会显示什么值呢?答案是“Type is Chicken”,
//根据上面的分析,想想到底为什么? 2.关于new关键字在虚方法动态调用中的阻断作用,也有了更明确的理论基础。
//在子类方法中,如果标记new关键字,则意味着隐藏基类实现,其实就是创建了与父类同名的另一个方法,
//在编译中这两个方法处于动态方法表的不同地址位置,父类方法排在前面,子类方法排在后面。 Console.WriteLine("bird2.Type is {0}", bird2.Type);
bird2.ShowType();
Console.ReadKey();
}
}
}
if(A的F is virtual)
{
if (B的F is override)
执行 B的F
else
执行A的F
}
else
执行A的F
------------
D d = new D();//新建对象d
A a = d;//??
B b = d;
C c = d;
这几个赋值式子该怎么理解呢?
A a = d; // 将d赋值给A 类型的对象a
B b = d; // 将d赋值给B 类型的对象b
C c = d; // 将d赋值给C 类型的对象c
因为ABC都是D的父类,所以可以这么赋值,输出应该是:
B.F
B.F
D.F
D.F