unity3d——关于GetComponent<T>()
先看代码:
TankBaseObj obj = other.GetComponent<TankBaseObj>();
if(obj != null)
{
//说明是坦克打到坦克 受伤处理 固定不会受伤 移动的会受伤
obj.Wound(fatherObj);
}
TankBaseObj 是一个基类 wound是一个虚函数 子类已经重新实现 当你的游戏对象依附的是一个已经继承TankBaseObj的子类 然后 TankBaseObj obj = other.GetComponent<TankBaseObj>(); obj 就是子类的实例化 只不过 这里是用父类装子类的思想 但是他实际的引用还是子类对象 并且 子类已经重写虚函数Wound 所以这里掉用的就会是重写的函数方法
在Unity中,当你使用GetComponent<T>()
方法获取组件时,你实际上是在尝试从游戏对象上获取类型为T
的组件。在你的例子中,T
是TankBaseObj
,这是一个父类。如果游戏对象上附加了一个继承自TankBaseObj
的子类组件(比如TankChildObj
),那么GetComponent<TankBaseObj>()
将会成功返回这个子类组件的实例,因为子类实例也是父类类型的一个对象。
现在,关于你提到的Wound
方法被重写的情况,这里有一些关键点需要理解:
-
虚方法和重写:如果
TankBaseObj
中的Wound
方法被标记为virtual
,并且子类(比如TankChildObj
)中提供了这个方法的一个override
实现,那么当通过父类类型的引用调用这个方法时,实际上会调用子类中的重写方法。这是C#中多态性的一个表现。 -
实际对象类型:在运行时,
obj
变量虽然被声明为TankBaseObj
类型,但它实际上指向的是子类(如TankChildObj
)的一个实例。因此,当调用obj.Wound(fatherObj);
时,会调用该实例上重写的Wound
方法。 -
编译时与运行时类型:在编译时,
obj
的类型是TankBaseObj
,编译器只知道它可以调用TankBaseObj
上定义的方法。但在运行时,obj
实际指向的是一个具体的子类实例,所以运行时会根据这个实例的实际类型来确定调用哪个Wound
方法。
举个例子,假设有以下类定义:
public class TankBaseObj : MonoBehaviour
{
public virtual void Wound(GameObject attacker)
{
// 父类的受伤处理逻辑
Debug.Log("TankBaseObj Wound");
}
}
public class TankChildObj : TankBaseObj
{
public override void Wound(GameObject attacker)
{
// 子类的受伤处理逻辑
Debug.Log("TankChildObj Wound");
// 可能还会调用base.Wound(attacker)来执行父类的逻辑
}
}
如果游戏对象上附加了TankChildObj
组件,并且你通过GetComponent<TankBaseObj>()
获取了这个组件,然后调用了Wound
方法,那么将会输出TankChildObj Wound
,因为实际调用的是TankChildObj
中重写的Wound
方法。
总结来说,当你通过父类类型的引用调用一个被子类重写的方法时,实际调用的是运行时对象类型中重写的方法。这是面向对象编程中多态性的一个基本特性。