C++多态分为编译时多态(函数重载、模板,编译期确定)和运行时多态(虚函数+继承,运行期通过虚表查表调用),前者依赖参数类型静态匹配,后者依赖对象实际类型动态分派。

多态调用中,参数的实际类型解析与值传递没有“先后顺序”的竞争关系——它们发生在不同阶段、由不同机制决定:参数类型在编译期静态确定,值传递是运行时按引用或值拷贝执行,而方法实际调用哪个版本(即多态性体现),取决于接收者(this)的运行时类型,与参数类型无关。
参数类型由编译器静态检查,不参与多态分派
Java 中方法重载(overload)看参数的声明类型,而多态(override)只看接收者的运行时类型。当你写 parent.doSomething(child):
- 编译器根据
parent的编译时类型(如Parent)和child的编译时类型(如Child或Parent)匹配重载方法签名 - 这个匹配过程在编译期完成,一旦确定了调用哪个重载方法(例如
doSomething(Child)还是doSomething(Parent)),就固定了方法入口 - 参数的实际运行时类型(比如 child 虽是
Child类型对象,但被向上转型为Parent引用传入)不影响方法选择,也不触发多态
值传递立即发生,但仅传递“引用值”或“基本值”
进入方法体前,JVM 执行参数传递:
- 如果是对象引用(如
Child child),传递的是该引用变量的副本(即内存地址值的拷贝),不是对象本身 - 如果是基本类型(如
int x),传递的是该数值的副本 - 这个过程不涉及类型解析,也不延迟;它紧随方法调用指令之后、方法体执行之前完成
真正体现多态的,只有方法主体内对 this 的调用
假设 parent 是 Parent 类型引用,实际指向 Child 对象,且 doSomething 在 Child 中被重写:
立即学习“Java免费学习笔记(深入)”;
-
parent.doSomething(child)调用的仍是Child.doSomething(...)(因为接收者this是Child实例) - 但注意:这个多态行为只作用于
doSomething方法自身,以及它内部通过this.xxx()调用的其他虚方法 - 参数
child在方法体内作为局部变量使用,其字段访问和方法调用,仍取决于它在该处的编译时类型(例如child.getName()调用哪个版本,看child声明类型,不是它实际是什么类)
一个典型易错场景:参数是父类类型,但传入子类实例
例如:
class Parent { void doSomething(Parent p) { System.out.println("Parent version"); } }
class Child extends Parent {
@Override void doSomething(Parent p) { System.out.println("Child version"); }
void doSpecial() { System.out.println("Child only"); }
}
Parent p = new Child();
Child c = new Child();
p.doSomething(c); // 输出 "Child version" —— 多态生效(因 p 是 Child 实例)
// 但若在 doSomething 内写 c.doSpecial(),会编译失败 —— 因 c 的声明类型是 Parent,没 doSpecial 方法


















