使用多态指针调用函数

时间:2015-09-15 15:49:44

标签: c++ inheritance

#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 *)。但编译器选择使用此方法的原则是什么?函数重载多态?任何拇指规则?

3 个答案:

答案 0 :(得分:5)

你的问题意味着你期望在f中被声明为f时你会得到的行为。在某些语言中,这是唯一可行的行为。在C ++中,您可以选择。

当你声明f时,它使用编译时类型,因此x-f(new AA)调用X::f,因为xX*

如果您在X中声明了f虚拟,则x-f(new AA)将调用Y::f,因为x指向Y

对于你问题的另一个方面(为什么在为Y类型的对象调用X :: f时没有涉及错误),X是Y的基类,所以应该有一个类型为X的有效对象在Y类型的每个对象中,X对象应该可以与任何X方法一起使用。

在看到上述评论之前,我错过了你的问题的第三个方面,当你将AA*传递给一个A*时,编译器推断出需要从AA*A*的隐式强制转换。需要AAA的方法是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*)

此外,由于AAA的子类,因此您可以将指针传递给AA指向A的指针。

答案 2 :(得分:1)

如果您希望x->f(new AA)致电Y::f(),则需要将X::f()声明为virtual.

如果X::f()未声明为virtual,则(xX指针)x->f(new AA)调用X::f()

参见C ++标准第10.3节&#34;虚函数&#34; (N3242):

  
      
  1. 虚函数支持动态绑定和面向对象编程。声明或的类   继承虚函数称为多态类。

  2.   
  3. 如果在类vf和类Base中声明了虚拟成员函数Derived,则直接或间接派生   从Base,声明了与vf同名的成员函数Base::vf,参数类型列表,cv资格和重新定义(或不​​存在相同),然后{{ 1}}也是Derived::vf(无论是否如此声明)并且它会覆盖virtual

  4.