2009-09-04 3 views
1

В настоящее время я работаю над проектом на C++, где у меня есть абстрактный интерфейс, который реализован позже. Интерфейс также имеет реализованный метод, который моя реализация не отменяет. Моя проблема заключается в том, что при использовании моей реализации компилятор (MSVC) не видит метод интерфейса. Что вызывает это, и как я могу его решить?виртуальный метод, не замеченный в реализации

Приходит код.

#include <string> 
#include <vector> 
using std::string; 

class A 
{ 
    public: 
    string name; 
}; 

class interface 
{ 
public: 
    virtual int num_foo() = 0; 
    virtual A* foo(int) = 0; 
    virtual A* foo(string &name){ 
     for (int i(0); i < num_foo(); i++) 
      if (foo(i)->name == name) 
       return foo(i); 
     return 0; 
    } 
}; 

class implementation : public interface 
{ 
public: 
    virtual int num_foo() { return m_foos.size(); } 
    virtual A* foo(int i) { 
     //check range 
     return &m_foos[i]; 
    } 
    std::vector<A> m_foos; 
}; 

int main(...) 
{ 
    implementation impl; 
    // impl is properly initialized here 

    string name("bar"); 
    // here comes my problem, the MSVC compiler doesn't see foo(string &name) 
    // and gives an error 
    A *a = impl.foo(name); 
} 
+2

Я вставил свой код в мой редактор, чтобы взглянуть на него, но я отказался от него после того, как я установил половину десяток ошибок, и он до сих пор не компилируется. Трудно ли предоставить код, в котором есть только одна проблема, о которой вы спрашиваете? Как бы то ни было, я не вижу, какие из десятков ошибок вы жалуетесь. Исправьте свой код. – sbi

+1

извините за плохой код. теперь я исправил ошибки, и теперь моя проблема присутствует. –

ответ

5

Разрешение имен происходит до разрешения перегрузки. В impl.foo(name) компилятор просматривает класс implementation и находит только virtual A& foo(int i). Он не смотрит на базовый класс, так как он нашел функцию с правильным именем.

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

(другие ошибки, которые вы не определяете string, vector или m_ones, вы пытаетесь использовать -> вместо . на ссылку, и вы пытаетесь вернуть 0 в функции, возвращающей ссылку на A.)

+0

+1 для четкого объяснения, а также двух предлагаемых обходных решений! – RichieHindle

+0

Спасибо, что ответили на мой вопрос и предвидели плохой код. –

3

Чтобы повторно публиковать базовые методы (например, Foo (строки)) в подклассе для перегрузки, добавьте

using interface::foo; 

в реализации класса.

+0

Спасибо за быстрый и хороший ответ! –

1
class implementation : public interface{ 
    public: 
     using interface::foo; 
     int num_foo() { return m_foos.size(); } 
     A& foo(int i) 
     { //check range 
      return m_ones[i]; 
     } 
     vector<A> m_foos; 
     vector<A> m_ones; 
}; 
0

Это только проблема, потому что вы обращаетесь к интерфейсу implementation, который не имеет foo элемент, как было отмечено уже в ответе на @ Шарль подол.

семантически, что вы пытаетесь назвать это interface метод Foo, так что вы, вероятно, следует на самом деле назвать это:

int main() 
{ 
    implementation impl; 
    string name("bar"); 
    interface& interf = impl; 
    A *a = interf.foo(name); 
    A *b = interf.foo(4); 
} 

Это также позволит Вам осуществить Non-Virtual Interface idiom, сделав implementation::foo личное. Если вы попытаетесь напрямую позвонить impl.foo, вы все равно потерпите неудачу, но вы будете терпеть неудачу для всех типов аргументов с той же ошибкой.

(я знаю, этот вопрос старый, но NVI старше ...)

Смежные вопросы