2014-02-21 4 views
1

У меня возникли проблемы с интерфейсами, наследованием и переопределением. В этом случае я не уверен, почему именно C++ ведет себя так, поэтому, если кто-то может объяснить и помочь мне с этим. У меня есть эти классы:C++: наследование функций и их переопределение

module.h:

class mixer; 

class module { 

public: 

    module(std::string name_) : name(name_) {} 
    ~module() {} 

    virtual module& bind(module &mod) = 0; 
    virtual module& bind(mixer &mix) { return ((module&)mix); } 

    std::string get_name() 
    { 
    return name; 
    } 

    std::string name; 
}; 

in_out.h:

class in_out : public module { 

public: 

    in_out(std::string name_) : module(name_) {} 
    ~in_out() {} 

    virtual module& bind(module &mod) 
    { 
    std::cout << "bind in_out in " << mod.name << std::endl; 
    return mod; 
    } 

}; 

prod.h:

class prod : public in_out { 

public: 

    prod(std::string name_) 
    : in_out(name_) 
    {} 

    ~prod() {} 

    virtual module& bind(mixer &mix) 
    { 
    std::cout << "bind mixer in " << get_name() << std::endl; 
    return mix; 
    } 

}; 

mixer.h:

class mixer : public in_out { 

public: 

    mixer(std::string name_) 
    : in_out(name_) 
    {} 

    ~mixer() {} 
}; 

Так, если в моем главном файле у меня есть это:

int main(int argc, char *argv[]) 
{ 
    prod prod1("prod1"); 
    prod prod2("prod2"); 
    mixer mixer1("mixer1"); 
    mixer mixer2("mixer2"); 

    prod1.bind(prod2); 

    return 0; 
} 

я получаю эту ошибку:

main.cpp: In function ‘int main(int, char**)’: 
main.cpp:12:19: error: no matching function for call to ‘prod::bind(prod&)’ 
main.cpp:12:19: note: candidate is: 
prod.h:19:23: note: virtual pfn_module& prod::bind(mixer&) 
prod.h:19:23: note: no known conversion for argument 1 from ‘prod’ to ‘mixer&’ 
make: *** [main] Error 1 

Если я вместо этого:

prod1.in_out::bind(prod2); 

Он работает, как ожидалось.

Что я не понимаю, разве компилятор не различает их?

virtual module& bind(module &mod) = 0; 
// and 
virtual module& bind(mixer &mix) { return ((module&)mix); } 

Я думаю, что проблема может быть, что оба mixer и prod являются потомком modulein_out). Может быть, когда функция bind вызывается в основном, она ищет ее в определении prod и находит только bind(mixer)? Как насчет bind(module)? Является ли он конфиденциальным в этом контексте?

То, что я хотел бы иметь, независимо от того, что я называю prod.bind(prod) или prod.bind(mixer), это отличает их prod «s уровне, так что я не должен позвонить .in_out оттуда.

Большое спасибо :)

ответ

3

Проблема заключается в том, что при определении класса тычок и объявлена ​​функция привязки

virtual module& bind(mixer &mix); 

в рамках класса вы прятались все другие функции с тем же именем базового класса , Итак, вы позвонили

prod1.bind(prod2); 

компилятор видит только один кандидат в классе: функция, показанная выше. И он не может преобразовать опорный код для ссылки на миксер.

Вы должны написать в определении класса

using in_out::bind; 

И как @Alex отметил в своем комментарии, вы должны сделать деструктор класса модуля виртуального, если вы используете полиморфизм.

EDIT: Если подставить pfn_inout для IN_OUT, потому что нет никакого определения pfn_inout то следующий код компилируется успешно

#include <iostream> 
#include <string> 

class mixer; 

class module { 

public: 

    module(std::string name_) : name(name_) {} 
    ~module() {} 

    virtual module& bind(module &mod) = 0; 
    virtual module& bind(mixer &mix) { return ((module&)mix); } 

    std::string get_name() 
    { 
    return name; 
    } 

    std::string name; 
}; 

class in_out : public module { 

public: 

    in_out(std::string name_) : module(name_) {} 
    ~in_out() {} 

    virtual module& bind(module &mod) 
    { 
    std::cout << "bind in_out in " << mod.name << std::endl; 
    return mod; 
    } 

}; 

class mixer : public in_out { 

public: 

    mixer(std::string name_) 
    : in_out(name_) 
    {} 

    ~mixer() {} 
}; 

class prod : public in_out { 

public: 
    using in_out::bind; 

    prod(std::string name_) 
    : in_out(name_) 
    {} 

    ~prod() {} 

    virtual module& bind(mixer &mix) 
    { 
    std::cout << "bind mixer in " << get_name() << std::endl; 
    return mix; 
    } 

}; 


int main() 
{ 
    prod prod1("prod1"); 
    prod prod2("prod2"); 
    mixer mixer1("mixer1"); 
    mixer mixer2("mixer2"); 

    prod1.bind(prod2); 

    return 0; 
} 
+1

также деструкторы базовых классов виртуальными. –

+0

@Alex Вы правы. Спасибо, я добавлю свой пост. –

+0

Хорошо. Делает много смысла :) Но я получаю эту ошибку: 'error: 'virtual module & in_out :: bind (module &)' isaccessible' – makeMonday

1

В C++, поиск имени останавливается в объеме, где находится имя. (Есть некоторые исключения, связанные с ADL, но они не применяются здесь .) Причина этого заключается в том, чтобы избежать изменения семантики функций в вашей производной, если имена добавлены в базовый класс .

Как правило, это не должно быть проблемой, поскольку вы должны реализовать все виртуальные функции в интерфейсе во всех производных классах. А виртуальные функции и не виртуальные функции не должны делить имена. В вашем случае, то, что вы, вероятно, хотите в базовом классе что-то вроде:

class Module 
{ 
private: 
    virtual Module& doBind(Module& mod) = 0; 

public 
    Module& bind(Module& mod) 
    { 
     // pre-conditions 
     Module& results = doBind(mod); 
     // post-conditions and invariants 
     return results; 
    } 
    Module& bind(Mixer& mix) 
    { 
     // pre-conditions 
     Module& results = doBind(static_cast<Module&>(mod)); 
     // post-conditions and invariants 
     return results; 
    } 
}; 

Производные классы будут реализовывать свои собственные версии doBind, но ничего.

Одна вещь, все же. Преобразование (Module&)mix, в контексте где компилятор не может видеть полное определение Module, является reinterpret_cast, что почти наверняка не, что вы хотите. В моем примере я использовал static_cast, чтобы выровнять с то, что вы сделали, но на самом деле это незаконно, если компилятор не видит определения Module. В этом конкретном случае фактически нет необходимости в том, что когда-либо было для второй функции bind , так как Mixer& будет конвертировать неявно в Module&, без необходимости конвертации с вашей стороны. (Но это вполне возможно, что этот код просто очень упрощенный пример, и , что в вашем реальном коде, вы на самом деле делать что-то более комплексов.)

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