C++ 继承共享方法名称的接口

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2004820/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 21:49:21  来源:igfitidea点击:

Inherit interfaces which share a method name

c++visual-c++gccmultiple-inheritance

提问by Gohan

There are two base classes have same function name. I want to inherit both of them, and over ride each method differently. How can I do that with separate declaration and definition (instead of defining in the class definition)?

有两个基类具有相同的函数名。我想继承它们,并以不同的方式克服每种方法。如何使用单独的声明和定义(而不是在类定义中定义)来做到这一点?

#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();
}   

I failed to move the definition out in VC8. I found the Microsoft Specific Keyword __interface can do this job successfully, code below:

我未能将 VC8 中的定义移出。我发现 Microsoft 特定关键字 __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();
}  

but is there another way to do this something more general that will work in other compilers?

但是有没有另一种方法可以在其他编译器中使用更通用的方法?

回答by Max Lybbert

This problem doesn't come up very often. The solution I'm familiar with was designed by Doug McIlroy and appears in Bjarne Stroustrup's books (presented in both Design & Evolution of C++section 12.8 and The C++ Programming Languagesection 25.6). According to the discussion in Design & Evolution, there was a proposal to handle this specific case elegantly, but it was rejected because "such name clashes were unlikely to become common enough to warrant a separate language feature," and "not likely to become everyday work for novices."

这个问题不经常出现。我熟悉的解决方案是由 Doug McIlroy 设计的,并出现在 Bjarne Stroustrup 的书中(出现在C++ 的设计与进化部分 12.8 和C++ 编程语言部分 25.6 中)。根据Design & Evolution 中的讨论,有一个提议可以优雅地处理这个特定情况,但被拒绝了,因为“这种名称冲突不太可能变得足够普遍以保证单独的语言特征”,并且“不太可能成为日常为新手工作。”

Not only do you need to call Name()through pointers to base classes, you need a way to say whichName()you want when operating on the derived class. The solution adds some indirection:

您不仅需要Name()通过指向基类的指针进行调用,而且在对派生类进行操作时,您还需要一种方法来说明您想要哪种方法Name()。该解决方案增加了一些间接性:

class Interface1{
public:
    virtual void Name() = 0;
};

class Interface2{
public:
    virtual void Name() = 0;
};

class Interface1_helper : public Interface1{
public:
    virtual void I1_Name() = 0;
    void Name() override
    {
        I1_Name();
    }
};

class Interface2_helper : public Interface2{
public:
    virtual void I2_Name() = 0;
    void Name() override
    {
        I2_Name();
    }
};

class RealClass: public Interface1_helper, public Interface2_helper{
public:
    void I1_Name() override
    {
        printf("Interface1 OK?\n");
    }
    void I2_Name() override
    {
        printf("Interface2 OK?\n");
    }
};

int main()
{
    RealClass rc;
    Interface1* i1 = &rc;
    Interface2* i2 = &rc;
    i1->Name();
    i2->Name();
    rc.I1_Name();
    rc.I2_Name();
}

Not pretty, but the decision was it's not needed often.

不漂亮,但决定是不经常需要它。

回答by Gohan

You cannot override them separately, you must override both at once:

您不能单独覆盖它们,您必须同时覆盖它们:

struct Interface1 {
  virtual void Name() = 0;
};

struct Interface2 {
  virtual void Name() = 0;
};

struct RealClass : Interface1, Interface2 {
  virtual void Name();
};
// and move it out of the class definition just like any other method:
void RealClass::Name() {
  printf("Interface1 OK?\n");
  printf("Interface2 OK?\n");
}

You can simulate individual overriding with intermediate base classes:

您可以使用中间基类模拟单个覆盖:

struct RealClass1 : Interface1 {
  virtual void Name() {
    printf("Interface1 OK?\n");
  }
};

struct RealClass2 : Interface2 {
  virtual void Name() {
    printf("Interface2 OK?\n");
  }
};

struct RealClass : RealClass1, RealClass2 {
  virtual void Name() {
    // you must still decide what to do here, which is likely calling both:
    RealClass1::Name();
    RealClass2::Name();

    // or doing something else entirely

    // but note: this is the function which will be called in all cases
    // of *virtual dispatch* (for instances of this class), as it is the
    // final overrider, the above separate definition is merely
    // code-organization convenience
  }
};

Additionally, you're using reinterpret_cast incorrectly, you should have:

此外,您使用 reinterpret_cast 不正确,您应该:

int main() {
  RealClass rc; // no need for dynamic allocation in this example

  Interface1& one = rc;
  one.Name();

  Interface2& two = dynamic_cast<Interface2&>(one);
  two.Name();

  return 0;
}

And here's a rewrite with CRTPthat might be what you want (or not):

这是使用CRTP重写的可能是您想要的(或不想要的):

template<class Derived>
struct RealClass1 : Interface1 {
#define self (*static_cast<Derived*>(this))
  virtual void Name() {
    printf("Interface1 for %s\n", self.name.c_str());
  }
#undef self
};

template<class Derived>
struct RealClass2 : Interface2 {
#define self (*static_cast<Derived*>(this))
  virtual void Name() {
    printf("Interface2 for %s\n", self.name.c_str());
  }
#undef self
};

struct RealClass : RealClass1<RealClass>, RealClass2<RealClass> {
  std::string name;
  RealClass() : name("real code would have members you need to access") {}
};

But note that here you cannot call Name on a RealClass now (with virtual dispatch, e.g. rc.Name()), you must first select a base. The self macro is an easy way to clean up CRTP casts (usually member access is much more common in the CRTP base), but it can be improved. There's a brief discussion of virtual dispatch in one of my other answers, but surely a better one around if someone has a link.

但请注意,现在您不能在 RealClass 上调用 Name(使用虚拟调度,例如rc.Name()),您必须首先选择一个基类。self 宏是一种清理 CRTP 强制转换的简单方法(通常成员访问在 CRTP 库中更为常见),但可以改进。在我的其他答案之一中简要讨论了虚拟调度,但如果有人有链接,肯定会更好。

回答by Len Holgate

I've had to do something like this in the past, though in my case I needed to inherit from one interface twice and be able to differentiate between calls made on each of them, I used a template shim to help me...

过去我不得不做这样的事情,但在我的情况下,我需要从一个接口继承两次并能够区分对每个接口进行的调用,我使用模板垫片来帮助我......

Something like this:

像这样的东西:

template<class id>
class InterfaceHelper : public MyInterface
{
    public : 

       virtual void Name() 
       {
          Name(id);
       }

       virtual void Name(
          const size_t id) = 0;  
}

You then derive from InterfaceHelpertwice rather than from MyInterfacetwice and you specify a different idfor each base class. You can then hand out two interfaces independently by casting to the correct InterfaceHelper.

然后您从InterfaceHelper两次派生而不是从MyInterface两次派生,并id为每个基类指定一个不同的。然后,您可以通过强制转换为正确的InterfaceHelper.

You could do something slightly more complex;

你可以做一些稍微复杂的事情;

class InterfaceHelperBase
{
    public : 

       virtual void Name(
          const size_t id) = 0;  
}


class InterfaceHelper1 : public MyInterface, protected InterfaceHelperBase
{
    public : 

       using InterfaceHelperBase::Name;

       virtual void Name() 
       {
          Name(1);
       }
}

class InterfaceHelper2 : public MyInterface, protected InterfaceHelperBase
{
    public : 

       using InterfaceHelperBase::Name;

       virtual void Name() 
       {
          Name(2);
       }
}

class MyClass : public InterfaceHelper1, public InterfaceHelper2
{
    public :

      virtual void Name(
          const size_t id)
      {
          if (id == 1) 
          {
              printf("Interface 1 OK?");
          }
          else if (id == 2) 
          {
              printf("Interface 2 OK?");
          }
      }  
}

Note that the above hasn't seen a compiler...

请注意,上面没有看到编译器......

回答by Jagannath

class BaseX
{
public:
    virtual void fun()
    {
        cout << "BaseX::fun\n";
    }
};

class BaseY
{
public:
    virtual void fun()
    {
        cout << "BaseY::fun\n";
    }
};


class DerivedX : protected BaseX
{
public:
    virtual void funX()
    {
        BaseX::fun();
    }
};

class DerivedY : protected BaseY
{
public:
    virtual void funY()
    {
        BaseY::fun();
    }
};


class DerivedXY : public DerivedX, public DerivedY
{

};

回答by Narfanator

There are two other related questions asking nearly (but not completely) identical things:

还有另外两个相关的问题问几乎(但不完全)相同的事情:

Picking from inherited shared method names. If you want to have rc.name() call ic1->name() oric2->name().

从继承的共享方法名称中挑选。如果你想要 rc.name() 调用 ic1->name()ic2->name()。

Overriding shared method names from (templated) base classes. This has simpler syntax and less code that your accepted solution, but does notallow for access to the functions from the derived class. More or less, unless you need to be able to call name_i1() from an rc, you don't need to use things like InterfaceHelper.

覆盖(模板化)基类中的共享方法名称。这有简单的语法和更少的代码,你接受的解决方案,但不会允许从派生类访问功能。或多或少,除非您需要能够从 rc 调用 name_i1(),否则您不需要使用 InterfaceHelper 之类的东西。