2014-02-08 4 views
2

У меня есть вопрос о вызове функции с виртуальными методами и множественным наследованием. у меня есть следующий код:виртуальные таблицы и наследование C++

#include<iostream> 
using namespace std; 
class A{}; 
class B:public A{}; 
class C:public B{}; 
class AA:public A{}; 
struct X 
{ 
    void f(A*) { std::cout<< "X::f(A*)\n";} 
    virtual void f(B*) { std::cout<< "X::f(B*)\n";} 
    void f(C*) { std::cout<< "X::f(C*)\n";} 
    virtual void f(C*) const { std::cout<< "const X::f(C*)\n";} 
}; 
struct Y:public X { 
    virtual void f(B*) { std::cout<< "Y::f(B*)\n";} 
    void f(A*) { std::cout<< "Y::f(A*)\n";} 
    virtual void f(C*) const { std::cout<< "const Y::f(C*)\n";} 
}; 
int main() { 
    Y* y=new Y(); 
    y->f(new C); 
} 

Я не могу понять, почему это получается неоднозначным и есть 2 кандидата:

Y::f(B*) 
Y::f(C*) 
+0

Где же это получается неоднозначным ? –

+0

, когда я пытаюсь скомпилировать код. – user3286882

+1

Что это связано с множественным наследованием? Каждый из ваших классов/структур наследуется от одного класса/структуры. – andrjas

ответ

4

Для перегрузки функции, которые будут выбран, он должен быть " наилучшим образом "при принятии каждого отдельного аргумента, включая неявный аргумент, который становится this. Best определяется в терминах наименьших преобразований, необходимых для преобразования аргумента (в вызывающем) в параметр (в вызываемом).

virtual void f(C*) const прекрасно согласуется с аргументом типа C*, но const классификатора в конце требует, чтобы this быть преобразован из неконстантных Y* к Y const *. Об этом жалуется компилятор. Если вы разыгрываете

static_cast< Y const * >(y)->f(new C); 

Проблема уходит (хотя это не сразу иллюстративное, так как дополнительная квалификация дисквалифицирует другие перегрузки).

Обратите внимание, что все перегрузки в X даже не проверяются. Разрешение имен, которое находит все перегруженные данные, начинается с производного класса и продолжается до ветвей наследования, пока не найдет соответствующее имя, , а затем оно остановится. Чтобы объединить функции из нескольких классов в один набор перегрузки, используйте объявление using внутри Y, using X::f;.

Фактическое решение этой проблемы, вероятно, заключается в том, чтобы ввести более соответствующие перегрузки без квалификаторов const в конце, поэтому квалификация вызывающего указателя const не играет такую ​​неинтуитивную роль.

+1

, но для использования Y :: f (B *) нужно будет преобразовать переменную вправо? и для Y :: f (C *) это точное совпадение. разве это не так? – user3286882

+0

@ user3286882 См. Edit; '' const '' на 'Y :: f (C *) const' делает его не точным. – Potatoswatter

+0

У меня создалось впечатление, что не const const (и наоборот) совпадает с точным соответствием. – user3286882

0

void f (C *) {std :: cout < < "X :: f (C *) \ n"; } в базовом классе не отображается из-за скрытия имени.

using X::f; в производном классе, и он работает должным образом.

2

Ваша перегрузка для C является единственной функцией члена-члена. y не const и все перегрузки f приемлемы, поэтому вызов неоднозначен.

пути для разрешения неоднозначности:

  • Добавить перегрузку нон константной для C
  • Марки у Const
  • Сделать перегруженные для A и B сопзЬ
Смежные вопросы