2015-09-15 2 views
1
#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); 
} 

Print:вызова к функциям с полиморфными указателями

X :: F (A *)

X :: F (A *)

Я не понять почему y->X::f(new AA) и x->f(new AA) wont повышение сбор ошибка. Я понимаю, что в обоих случаях вызывается X::f(A *). Но каков принцип, по которому компилятор предпочитает использовать этот метод? Функциональная перегрузка с полиморфизмом? Любые правила большого пальца?

+0

Зачем вам ожидать ошибки на самом деле? Я не понимаю. –

+0

В первом случае (** x-> f (новый AA) **) x является указателем на базовый класс X, поэтому вызывает _X :: f (A *) _. Во втором случае (** y-> X :: f (новый AA) **) вы явно сказали, что вас интересует метод из базового класса, написав ** X :: **. –

+0

Так много «новых» ... :-( – Jarod42

ответ

5

Ваш вопрос подразумевает, что вы ожидали поведения, которое вы бы получили, если f было объявлено виртуальным в X. На некоторых языках это единственно возможное поведение. В C++ у вас есть выбор.

Как вы объявили п, он использует время компиляции типа, чтобы x-f(new AA) звонков X::f потому что x является

Если бы вы объявили е виртуального в умноженной x-f(new AA) бы назвать Y::f, потому что х точки на Y

Для другого аспекта вашего вопроса (почему нет ошибки при вызове X :: f для объекта типа Y), X является базовым классом Y, поэтому должен быть действительный объект типа X, зарытый внутри каждого объект типа Y и этот объект X должен использоваться любым методом X.

До увидеть комментарии выше, я не пропустил третий аспект вашего вопроса, что компилятор выводит необходимость неявные отлитый из AA* к A*, когда вы передаете AA* к способу, который нуждается в A* и A является базовым классом от AA. Этот вычет в основном отдельно от времени компиляции или выполнения выбора времени между X :: F и Y :: е

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.

1

Если вы хотите x->f(new AA) позвонить Y::f(), то вам нужно объявить X::f(), как virtual.

Если X::f() не объявлен как virtual, то (как x является X указатель) x->f(new AA) вызывает X::f().

См. Раздел 10 стандарта C++.3 "Виртуальные функции" (N3242):

  1. Виртуальные функции поддерживают динамическое связывание и объектно-ориентированное программирование. Класс, объявляющий или наследует виртуальную функцию, называется полиморфным классом.

  2. Если виртуальная функция-член vf объявляется в классе Base и в классе Derived, полученная прямо или косвенно от Base, функции члена vf с тем же именем, параметр типа-лист, резюме-квалификация, и refqualifier (или его отсутствие), как Base::vf, то Derived::vf также является virtual (независимо от того, объявлен он или нет), и он переопределяет Base::vf.