在编译器中隐藏对象类型
本文关键字:对象 类型 隐藏 编译器 | 更新日期: 2023-09-27 18:03:45
我在一次面试中被问到这个问题。这让我措手不及。
你有一个超类和一个子类。类B
是A
的一个子类。这两个类都实现了相同的函数foo()
。
是否有可能编写一段代码,使编译器不知道对象的类型是什么?本例中对象为下面的b
。
A b = new B();
那么你可以调用一个函数,在执行之前不知道该函数的类型。
这是我在白板上的答案:(A)b.foo();
在c#中,您可以使用dynamic
关键字来实现动态类型。
public void MyMethod(dynamic myVar)
{
// The compiler don't know the exact type of myVar
// Does myVar have a foo() method? if not, we get a runtime error.
myVar.foo();
}
然而,我不认为这是他们正在寻找的答案,因为提到了A
和B
(并且它应该适用于Java和c#)。
他们可能一直在寻找的(基本上就是你自己说的)可能是这样的:
public void MyMethod(A a)
{
a.foo(); // What foo() method is called? The one from A or the one from B?
}
您可以使用A
和B
的实例作为MyMethod
的参数,因为B
与A
具有is-a关系(它继承)。编译器将a
视为A
的实例,尽管它可能是B
的实例。
调用了哪个foo()
方法?这取决于B
是覆盖A
对foo()
的实现还是隐藏它。如果它隐藏了它,A
的方法被调用,这是在编译时确定的,a
实际是什么类型并不重要。
如果它覆盖了foo()
(这是最有可能的情况),那么它在运行时被确定。由于编译器不知道a
的确切类型,因此在运行时根据a
的运行时类型查找要调用的正确方法。
所以编译器知道类型(如果是一个 作为旁注。A
),但是它不知道确切的类型(它是不是一个子类?)(A)b.foo();
会将foo()
返回的值强制转换为A
。如果您想在调用foo()
之前将b
转换为A
,您应该添加一组额外的括号:((A)b).foo();
。然而,强制转换是不必要的,因为b
已经被声明为A
变量(A b = ..
)。
你可以使用反射来创建编译器不知道的某种类型的对象(只有在运行时才会解析)。
如果你特别指的是语句new B(),那么不是——你是在告诉编译器正在创建什么类型。
至少在c#中你可以使用动态,编译器会在运行时输入代码来确定类型。