#include <iostream>
class A{};
class AA:public A{};
struct X {
void f(A *) {
std::cout << "X::f(A*)\n";
}
};
struct Y:public X {
void f(A *) {
std::cout << "Y::f(A*)\n";
}
};
int main() {
Y *y = new Y();
X *x = new Y();
const X *cx = new Y();
y->X::f(new AA);
x->f(new AA);
}
打印:
X :: f(A *)
X :: F(A *)
我不明白为什么y->X::f(new AA)
和x->f(new AA)
不会引发编译错误。我知道在两种情况下都会调用X::f(A *)
。但编译器选择使用此方法的原则是什么?函数重载多态?任何拇指规则?
答案 0 :(得分:5)
你的问题意味着你期望在f中被声明为f时你会得到的行为。在某些语言中,这是唯一可行的行为。在C ++中,您可以选择。
当你声明f时,它使用编译时类型,因此x-f(new AA)
调用X::f
,因为x
是X*
如果您在X中声明了f虚拟,则x-f(new AA)
将调用Y::f
,因为x指向Y
对于你问题的另一个方面(为什么在为Y类型的对象调用X :: f时没有涉及错误),X是Y的基类,所以应该有一个类型为X的有效对象在Y类型的每个对象中,X对象应该可以与任何X方法一起使用。
在看到上述评论之前,我错过了你的问题的第三个方面,当你将AA*
传递给一个A*
时,编译器推断出需要从AA*
到A*
的隐式强制转换。需要A
和AA
的方法是String path = System.getProperty("user.dir") + "/src/main/java/resources/file.txt";
的基类。该推论在很大程度上与X :: f和Y :: f
答案 1 :(得分:1)
您的代码目前的方式,如果您这样做:
y->X::f(new AA);
y->f(new AA);
x->f(new AA);
你会得到这个:
X::f(A*)
Y::f(A*)
X::f(A*)
但是,如果您将X::f
声明为虚拟,那么您将获得此信息:
X::f(A*)
Y::f(A*)
Y::f(A*)
此外,由于AA
是A
的子类,因此您可以将指针传递给AA
指向A
的指针。
答案 2 :(得分:1)
如果您希望x->f(new AA)
致电Y::f()
,则需要将X::f()
声明为virtual.
如果X::f()
未声明为virtual
,则(x
为X
指针)x->f(new AA)
调用X::f()
。
参见C ++标准第10.3节&#34;虚函数&#34; (N3242):
虚函数支持动态绑定和面向对象编程。声明或的类 继承虚函数称为多态类。
- 醇>
如果在类
vf
和类Base
中声明了虚拟成员函数Derived
,则直接或间接派生 从Base
,声明了与vf
同名的成员函数Base::vf
,参数类型列表,cv资格和重新定义(或不存在相同),然后{{ 1}}也是Derived::vf
(无论是否如此声明)并且它会覆盖virtual
。