假设我有一个基类和一个派生类。
class Base {
public:
void A(int x, int y) {do something}
void B() {
A(x,y);
do something;
}
};
class Derived : public Base {
void A() {do something else};
};
Derived derived1;
derived1.B();
函数的签名是不同的,B会调用派生的A还是基础A?如果它会调用派生的B,我猜它会忽略参数吗?
如果派生的A需要不同的参数而不是没有参数,我是否必须将B的整个代码复制到派生类中才改变B调用A的方式?
答案 0 :(得分:2)
函数的代码始终在定义它的类的上下文中进行计算。这包括确定每个表达式调用哪个函数。因此,在Base::B()
内,编译器将调用A(x, y)
转换为对Base::A
的调用。即使您稍后调用derived1.B()
,它也会调用derived1 . Base::A
(伪语法)。
唯一稍微改变这一点的是虚函数。然而,即使有它们,规则也是相似的。重载决策(基本上是将函数名称和签名与调用表达式匹配的过程)是在定义包含函数的类的上下文中完成的。如果解析导致选择虚函数,则将在运行时调用虚拟调用机制以调用该函数的适当覆盖。
让我们考虑这个例子:
struct Base {
virtual void foo(int);
virtual void bar() { foo(0.0); }
};
struct Derived : Base {
virtual void foo(int);
virtual void foo(double);
};
Derived d;
d.bar();
即使在此示例中,调用d.bar()
也会调用Derived::foo(int)
。这是因为调用签名匹配是在Base
的上下文中完成的,foo(int)
仅查看double
并使用从int.
到{{1}}的隐式转换
答案 1 :(得分:0)
有两个原因迫使Base::B
拨打Base::A
而不是Derived::A
A
:A(int, int)
Base::A
和Base::B
不是虚拟的,因此会调用Base::A
。代码不是多态的。
显示虚拟方法如何工作的最简单示例是:
class Base {
public:
virtual void A() {
// do job #1
}
};
class Derived : public Base {
public:
virtual void A() {
// do job #2
}
};
// ...
Derived derived1;
Base *base = &derived1;
base->A(); // <---- It calls `Derived::A()` and does job #2
但是,如果在A
中使用不同的参数(重载它)编写B
,则必须使用实际参数显式调用它。