我在接口,继承和重新定义方面遇到了一些问题。在这种情况下,我不确定为什么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
都是module
(和in_out
)的孩子。也许当在main中调用函数bind
时,它会在prod
的定义中查找它,并且只找到bind(mixer)
?那么bind(module)
呢?在这种情况下它是私有的吗?
我想要的是,无论我拨打prod.bind(prod)
还是prod.bind(mixer)
,它都会在prod
的级别区分它们,所以我不必致电{ {1}}从那里开始。
非常感谢:)
答案 0 :(得分:3)
问题是当你定义了类prod并声明了函数bind
virtual module& bind(mixer &mix);
在类范围中,您隐藏了具有相同基类名称的所有其他函数。那么你打电话给
prod1.bind(prod2);
编译器在类范围内只看到一个候选者:上面显示的函数。并且它无法将参考产品转换为参考混频器。
你应该在课程定义中写一下
using in_out::bind;
正如 @Alex 在他的评论中指出的那样,如果使用多态,你必须使类模块的析构函数成为虚拟。
编辑:如果要将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 :(得分:1)
在C ++中,名称查找在找到名称的范围内停止。 (有一些例外,与ADL相关,但它们不适用 这里。)原因是为了避免改变语义 如果将名称添加到Base,则派生中的函数 类。
通常,这应该不是问题,因为你应该这样做 在所有的接口中实现所有虚函数 派生类。而虚拟功能和非虚拟功能 函数不应共享名称。在你的情况下,你是什么 可能在基类中想要的是:
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&
,
无需您进行转换。 (但它确实如此
可能这个代码只是一个非常简单的例子,而且
在你的真实代码中,你实际上正在做更多的事情
复杂。)