这是一个在线解释的难题,但我会尽我所能。我已经实例化了一个B类型的对象,它存储在A类型的变量中。我使用了get类型属性,所以现在它是类型B.因此我执行了类型A和B的隐式转换。所以当a。时。 show()被称为B类型?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class A
{
public virtual void show()
{
Console.WriteLine("Showing A");
}
public void test()
{
Console.WriteLine("called from A");
}
}
class B:A
{
public override void show()
{
Console.WriteLine("Showing B");
}
public void testb()
{
Console.WriteLine("called from B");
}
}
class Program
{
static void Main(string[] args)
{
A a = new B();
// Outputs ConsoleApplication.B
Console.WriteLine("{0}", a.GetType());
// outputs showing B
a.show();
// outputs called from A
a.test();
Console.ReadLine();
}
}
}
答案 0 :(得分:3)
您尚未执行隐式转换,因为您实际上没有转换任何内容。
A a = new B();
您已直接实例化了类型B的对象。您可以从类型A的变量引用它,因为B是A的子类。但是,这两个操作应该被视为独立的。
... = new B();
无论左边是什么,总会实现类型B的对象。
A a = ...
将始终尝试将右侧的内容分配给变量a。
引用类型的唯一区别在于CLR如何看到对象。
A a = new B();
B b = new B();
两者都是B类的对象。但是,'a'只允许你使用它,就像它是A类型的对象一样。所以,你只能调用a.show()和a.test() ,即使它实际上是B类型,所以也有额外的方法testb()。 'b'允许你调用b.show(),b.test()和b.testb()。无论变量类型如何,当您调用show()时,它都是b类型,因此它是返回的重写show()方法。
最后,你现在可以做的是沮丧。即你实例化了一个B类对象,所以你现在可以将它转换为b类型的变量,这样就可以完全访问所有B类成员。
e.g:
A a = new B();
a.testb(); // this will not compile as a does not have a definition of testb().
A a = new B();
B b = (B)a; // downcast a to a reference of type B
b.testb(); // this is now fine
我刚刚看到你的另外一个问题,你为什么要将某些东西设为A类,即基类。这是为了与不同类型的对象一起工作的方式提供共同点。例如,你可能有一个基本类型的动物,并从它的几个子类 - 猫,狗,沙鼠。但是,您可能希望能够将所有动物的列表传递给只需要使用公共属性的方法。因此,如果Animal有一个名字,你的List可以被迭代并且每个动物名称被引用,即使Animal本身可以是Abstract(不能被实例化)并且该列表完全由Dogs,Cats和Gerbils组成。然后,您还可以通过找出与其进行进一步交互的类型来降低各种动物,例如
if (animal is Dog) {
Dog dog = (Dog)animal;
}
或者您可以使用'as'关键字进行演员:
Dog dog = animal as Dog;
希望这有帮助。
答案 1 :(得分:2)
仅仅因为你将它存储在Type A的变量中,你的变量仍然引用了Type B的对象。当你对变量“a”进行调用时,CLR知道要调用的正确方法。由于您覆盖了show方法,因此将调用B类型的show方法。但是你没有覆盖test(),所以调用了类型A的方法实现。这是可能的,因为B“继承”了A的test()行为,但没有覆盖它。
答案 2 :(得分:1)
在您的代码中:
// outputs showing B
a.show();
打印“显示B”,因为show()
是一种虚拟方法。任何虚方法调用都由对象类型决定,而不是引用的类型(后期绑定)。引用a
指向B
类型的对象。
// outputs called from A
a.test();
test()
只是继承自类A
而不是虚方法,因此它打印“从A调用”。方法调用a.GetType()
不会转换任何内容,它只返回一个Type-object的实例。
答案 3 :(得分:0)
变量a
指向B
类型的实例,因此a.show()
方法不需要转换B.show()
。这正是虚拟方法应该做的事情:在变量引用的实例化类型(或继承链中的第一个实现)上调用方法,而不是变量的声明类型。
对a.test()
的调用不会这样做,因为该方法未声明为virtual
。所以它只是调用A.test()
方法。
答案 4 :(得分:0)
正如其他帖子中所提到的,您创建了一个B类实例,但由于您将对象升级为A类,因此您为A类定义了接口。
如果需要访问为类型B定义的方法,可以将对象向下转换为原始类型,为您提供类型B的定义。
例如:
if (a is B)
{
((B)a).testb();
}
// or
B b = a as B;
if (b != null)
{
b.testb();
}