有两个基类具有相同的函数名。我想继承这两个方法,并以不同的方式重写每个方法。如何使用单独的声明和定义(而不是在类定义中定义)来实现这一点?
#include <cstdio>
class Interface1{
public:
virtual void Name() = 0;
};
class Interface2
{
public:
virtual void Name() = 0;
};
class RealClass: public Interface1, public Interface2
{
public:
virtual void Interface1::Name()
{
printf("Interface1 OK?\n");
}
virtual void Interface2::Name()
{
printf("Interface2 OK?\n");
}
};
int main()
{
Interface1 *p = new RealClass();
p->Name();
Interface2 *q = reinterpret_cast<RealClass*>(p);
q->Name();
}
我在VC8中没有把定义移出来。我发现Microsoft Specific Keyword __interface可以成功完成这项工作,代码如下:
#include <cstdio>
__interface Interface1{
virtual void Name() = 0;
};
__interface Interface2
{
virtual void Name() = 0;
};
class RealClass: public Interface1,
public Interface2
{
public:
virtual void Interface1::Name();
virtual void Interface2::Name();
};
void RealClass::Interface1::Name()
{
printf("Interface1 OK?\n");
}
void RealClass::Interface2::Name()
{
printf("Interface2 OK?\n");
}
int main()
{
Interface1 *p = new RealClass();
p->Name();
Interface2 *q = reinterpret_cast<RealClass*>(p);
q->Name();
}
但是有没有其他的方法可以做到这一点,一些更通用的方法可以在其他编译器中工作?
5条答案
按热度按时间rryofs0p1#
这个问题不常出现。我熟悉的解决方案是由Doug McIlroy设计的,出现在Bjarne Stroustrup的书中(在 Design & Evolution of C++ 第12.8节和 The C++ Programming Language 第25.6节中都有介绍)。根据《设计与进化》中的讨论,有一个建议是优雅地处理这个特定的情况,但它被拒绝了,因为“这样的名称冲突不太可能变得足够普遍,以保证一个单独的语言功能”,“不太可能成为新手的日常工作”。
不仅需要通过指向基类的指针调用
Name()
,还需要在对派生类进行操作时说明需要 * 哪个 *Name()
。解决方案增加了一些间接性:不太好,但决定是不经常需要。
zmeyuzjn2#
您不能单独覆盖它们,必须同时覆盖两者:
您可以使用中间基类模拟单独的重写:
另外,你错误地使用了reinterpret_cast,你应该:
这里有一个用CRTP重写的代码,这可能是你想要的(也可能不是):
但是请注意,这里您现在不能在RealClass上调用Name(使用虚拟分派,例如
rc.Name()
),则必须先选择一个基础。self宏是清理CRTP强制转换的一种简单方法(通常成员访问在CRTP库中更为常见),但它可以是improved。在我的另一个答案中有一个关于虚拟调度的简短讨论,但如果有人有链接,肯定会有一个更好的答案。qmelpv7a3#
过去我不得不做这样的事情,尽管在我的情况下,我需要从一个接口继承两次,并且能够区分对每个接口的调用,我使用了模板shim来帮助我。
大概是这样的:
然后从
InterfaceHelper
派生两次而不是从MyInterface
派生两次,并为每个基类指定不同的id
。然后,您可以通过转换为正确的InterfaceHelper
来独立地分发两个接口。你可以做一些稍微复杂一点的事情;
请注意,上面还没有看到编译器...
1qczuiv04#
xv8emn3q5#
还有另外两个相关的问题,问的是几乎(但不完全)相同的问题:
从继承的共享方法名称中选取。如果你想让rc.name()调用ic 1->name()或ic 2->name()。
Overriding shared method names from (templated) base classes。这比你接受的解决方案有更简单的语法和更少的代码,但是 * 不 * 允许从派生类访问函数。或多或少,除非您需要能够从rc调用name_i1(),否则您不需要使用InterfaceHelper之类的东西。