具有显式派生方法的C++接口

C++ Interface With Explicit Derived Methods

本文关键字:C++ 接口 方法 派生      更新时间:2023-10-16

我有一个示例接口,它将行为委托给实现类:

class IBase
{
public:
    virtual void Do(IBase* base) = 0;
    virtual std::string name() = 0;
};

然后我有1..N类实现IBase:

class A : public IBase
{
public:
    virtual void Do(IBase* base);
    virtual std::string name() { return "A"; }
};
class B : public IBase
{
public:
    virtual void Do(IBase* base);
    virtual std::string name()  { return "B"; }
};

然后,我希望Do()方法的主体调用为实现IBase:的所有对象定义的自由方法

void method(A* a, B* b)
{
    std::cout << a->name() << " " << b->name() << std::endl;
}
void method(B* b, A* a)
{
    method(b, a);
}

这不会编译,因为使用此代码,IBase无法解析为派生类型:

void Test::Run()
{
    IBase* a = new A();
    IBase* b = new B();
    b->Do(a);
}

我该如何完成这项工作或类似的工作?免费方法实现了所有可能的组合,似乎有一个技巧可以让IBase*在其中一个重载中被接受。

其次,在每个实现者都有一个接受接口的共享方法的情况下,如何实现接口方案?也许只使用免费方法并从IBase接口中删除Do(IBase*)可以更好地实现这一点。

编辑:如果(a)被声明为类型a,它就可以工作。让上面的代码与IBase一起工作的最佳方法是什么?

void Test::Run()
{
    A* a = new A();
    IBase* b = new B();
    b->Do(a);
}

我正在编译的文字代码:

class IBase
{
public:
    virtual void Do(IBase* base) = 0;
    virtual std::string name() = 0;
};
class A : public IBase
{
public:
    virtual void Do(IBase* base);
    virtual std::string name();
};
class B : public IBase
{
public:
    virtual void Do(IBase* base);
    virtual std::string name();
};
class Test
{
public:
    static void Run();
};
namespace
{
    void method(A* a, B* b)
    {
        std::cout << a->name() << " " << b->name() << std::endl;
    }
    void method(B* b, A* a)
    {
        method(b, a);
    }
}
void A::Do(IBase* base)
{
    method(this, base);
}
std::string A::name()
{
    return "A";
}
void B::Do(IBase* base)
{
    method(this, base);
}
std::string B::name() 
{
    return "B";
}
void Test::Run()
{
    IBase* a = new A();
    IBase* b = new B();
    b->Do(a);   
}

Visual Studio 2013:

错误1错误C2665:"anonymous-namespace'::method' : none of the 2 overloads could convert all the argument types Error 2 error C2665: '匿名命名空间"::方法":2个重载都无法转换所有参数类型

所以,如果我理解正确,你希望A::Do看起来像这样:

void A::Do(IBase* other) {
   if other is A, then call:
      method(this,other) for arguments A,A
   else if other is B, then call
      method(this,other) for arguments A,B
   etc.
}

对此有两个答案。最好的方法通常是更改设计。使方法成为IBase中的虚拟函数,而不是自由函数,并将a和B特定的任何函数提取到另一个虚拟函数中。

class IBase
{
public:
    virtual void Do(IBase* base) = 0;
    virtual std::string name() = 0;
    virtual void method(IBase* other);
    virtual void method2() = 0;
};
void IBase::method(IBase* other) {
    std::cout << name() << " " << other->method2() << std::endl;
}

另一种选择是使用类型铸造:

void A::Do(IBase* other) {
   if other is A, then call:
      method(this,dynamic_cast<A*>(other)))
   else if other is B, then call
      method(this,dynamic_cast<B*>(other))
   etc.
}

这种方法通常不能很好地扩展,很难维护并且容易出错。