【问题标题】:How to have two pure virtual methods with the same name but different return types如何拥有两个同名但返回类型不同的纯虚方法
【发布时间】:2018-05-30 16:05:56
【问题描述】:

我有一个公开可用的接口A,以及一个后端实现类C,如下所示:

struct A
{
    virtual void f() = 0;
};

struct C : public A
{
    virtual void f() override
    {
    }
};

我想逐步迁移到新界面B。 B 将具有相同的方法,但是返回类型可能不同。我希望我的实现类同时实现A 和B,以便遗留代码可以继续使用A,直到它被迁移,但是可以使用B 编写新代码。我知道如果我有两个签名完全相同的纯虚方法,我只需要在我的实现类中重写一个。但是如果它们的返回类型不同,我不知道该怎么做......

struct A
{
    virtual void f() = 0;
};

struct B
{
    virtual int f() = 0;
};


struct C : public A, public B
{
    // How do I implement both versions of f() here??
};

【问题讨论】:

  • 您不能仅根据返回值重载。您需要给B::f() 提供一组不同的参数,或者将其重命名为其他名称。
  • 你没有 - 你,你实现了实现各种 f() 的类 D 和 E,然后继承它们。
  • 即使你同时拥有两者,cObj.f() 也会模棱两可
  • 尝试模板化你的接口,以便相同的接口可以用于不同的数据类型作为返回值
  • 假设您正在编写应该通过C 使用B 接口的新代码。您希望新代码如何告诉C 将使用B 接口? (一旦您回答了这个问题:通过使用具有两个接口的单个​​类,您可以获得什么好处?)

标签: c++ overloading multiple-inheritance pure-virtual


【解决方案1】:

我会这样做

struct A {}
struct B {}
struct OldImpl : public A {}
struct NewImpl : public B {}
struct Combined : public AImpl, public BImpl {}

然后,您可以将组合传递给任何想要 A 或 B 的东西。 问题在于您的 OldImpl 和 NewImpl 是完全分开的。他们不允许互相交流;这意味着您不能在 A 中调用 setFoo() 并在 B 中的 getFoo() 中获得相同的值。这可能不是您所描述的内容。

要解决此问题,请不要创建第二个接口。无论如何它都行不通,因为 xxx() 现在可能是无效的,而稍后是 int,您可能想对返回值做一些事情。如果你真的想一步一步地做,创建一个分支,更改单个函数的返回值,测试它,合并它,重复。

【讨论】:

    【解决方案2】:

    感谢您的好评!但我确实找到了自己的解决方案:好旧的可选参数!

    struct A
    {
        virtual void f() = 0;
    };
    
    struct B
    {
        virtual int f(int ignoreMe = 0) = 0;
    };
    
    
    struct C : public A, public B
    {
        virtual void f() override {}
        virtual int f(int) override {}
    };
    

    外部用户使用A或B没有歧义,也不需要更改任何参数。内部也没有歧义,因为参数在实现类中是非可选的。迁移完成后,可以删除可选参数以及 A。

    【讨论】:

    • 非常骇人听闻的设计!
    【解决方案3】:

    这至少可以用 VS2017 编译:

    struct A
    {
        virtual void f() = 0;
    };
    
    struct A2: public A
    {
        void f() { Af(); }
        virtual void Af() = 0;
    };
    
    struct B
    {
        virtual int f() = 0;
    };
    
    struct B2 : public B
    {
        int f() { return Bf(); }
        virtual int Bf() = 0;
    };
    
    struct C : public A2, public B2
    {
        void Af() {}
        int Bf() { return 42; }
    };
    

    编辑:无法对 Paul Accisano 自己的回答添加评论,所以我把它放在这里。

    稍微修改保罗的回答。通过将未使用的默认参数设置为受保护类,您仍然可以进行正确的类型检查,并避免与其他成员函数发生类型冲突的可能性。

    struct A
    {
        virtual void f() = 0;
    };
    
    struct B
    {
    protected:
        class disambiguator {};
    public:
        virtual int f(disambiguator ignoreMe = disambiguator()) = 0;
    };
    
    
    struct C : public A, public B
    {
        virtual void f() override {}
        virtual int f(disambiguator ignoreMe) override { return 42; }
    };
    
    A *createA() { return new C; }
    B *createB() { return new C; }
    

    这方面的一个应用可能是从原始指针逐渐迁移到智能指针。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-07-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多