2009-09-26 5 views
4

Это не работает:Что происходит с переопределением и перегрузкой здесь на C++?

class Foo 
{ 
public: 
    virtual int A(int); 
    virtual int A(int,int); 
}; 
class Bar : public Foo 
{ 
public: 
    virtual int A(int); 
}; 

Bar b; 
int main() 
{ 
    b.A(0,0); 
} 

кажется, что, перекрывая Foo::A(int) с Bar::A(int) я как-то скрытый Foo::A(int,int). Если я добавлю Bar::A(int,int), все будет работать.

У кого-нибудь есть ссылка на хорошее описание того, что здесь происходит?

+0

Возможный дубликат: http://stackoverflow.com/questions/411103/function-with-same-name-but-different-signature-in-derived-class –

ответ

5

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

Возможные решения включают добавление директивы using Foo::A; в ваш производный класс, чтобы все элементы базового класса, называемые A, были видны в производном классе или с использованием разных имен для функций с различными сигнатурами.

См. Также here.

+0

Приятно получить мои подозрения подтвердились. Вы знаете ссылку на полное описание этого угла C++? – BCS

+1

Скрытие имени описано в 3.3.7 [basic.scope.hiding] стандарта, поиск имени - это весь 3.4 [basic.lookup], и есть целая глава (13 [over]) при перегрузке и разрешении перегрузки. Основное правило для вашей ситуации так же, как я описал. –

2

Там в обсуждении там здесь: http://bojolais.livejournal.com/222428.html

Затруднение это: В C++, если у вас есть класс с перегруженным методом (функцией, что вы хотите назвать его), а затем вы расширить и переопределение этот метод, вы должны переопределить все перегруженного метода

обойти это изменить вызов:

b.Foo::A(0, 0); 
0

Самый простой способ думать об этом стоит помнить, что перегрузка всегда происходит в пределах одной области, в то время как появляется между областями. Когда вы выясните, какую функцию вызывать, компилятор FIRST ищет, чтобы найти ближайшую область, которая имеет имя, а затем разрешает перегрузку между определениями в этой области.

0

Чтобы добавить к выше ответов,

Вы также можете определить перегруженную функцию в рамках Bar, который всегда вызывает ту же функцию в объеме Foo, если это предполагаемый результат. Это упрощает просмотр кода, как и ожидалось.

2
// I think this kind of approach is best to avoid this kind of problems. 

class Foo 
{ 
private: 
    virtual int A_impl(int);  // note the private declaration 
    virtual int A_impl(int,int); // of the actual implementation. 
           // clients have access through the 
           // non-virtual interface. 

public: 
    inline int A(int x) 
    {       // the non virtual interface will always be visible. 
     return A_impl(x);  // and consistent. 
    } 
    inline int A(int x, int y) 
    { 
     if (x != y) {   // also permits global parameter validation 
      return A_impl(x, y); // and it's easier to set breakpoints on a 
     }      // single entry point. 
     return 0; 
    } 
}; 
class Bar : public Foo 
{ 
private: 
    virtual int A_impl(int); 
}; 

Bar b; 
int main() 
{ 
    b.A(0,0);     // never again stuff like: ((A*)&b)->A(0,0) 
}