【问题标题】:interface implementation with additional default arguments?具有附加默认参数的接口实现?
【发布时间】:2013-09-07 16:22:32
【问题描述】:

我有一个关于在 C++ 中实现接口的问题:

假设有一个接口:

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

在实现这一点时,我想知道是否有办法执行以下操作:

class B : public A {     
  void f(int arg=0) {....} // unfortunately it does not implement f() this way
};

我想保持 iterface 干净。当客户端代码通过公共接口 A 调用时,arg 总是自动设置为 0。但是,当我通过 B 调用它时,我可以灵活地调用它,并将 arg 设置为一些不同的值。可以实现吗?

编辑:由于我控制界面和实现,我愿意接受任何建议、宏、模板、仿函数或任何其他有意义的东西。我只想拥有一个最小且干净的代码库。这个类很大,我不想编写任何非绝对必要的代码 - 例如。另一个简单地转发到实际实现的函数。

EDIT2:只是想澄清一下:公共接口提供给客户端。它比仅在内部使用的 B 类接口更严格。然而,函数 f() 基本上做同样的事情,除了基于输入 arg 的细微不同处理。真实类的接口函数比较多,签名比较复杂。快速进行函数转发会导致繁琐的代码重复,并且会污染 B 的内部接口。我想知道在 C++ 中处理这个问题的最佳方法是什么。

谢谢!

【问题讨论】:

    标签: c++ oop


    【解决方案1】:

    是的,只需制作两个单独的函数:

    class B : public A {     
        void f() { return f(0); }
        void f(int arg) { .... }
    };
    

    【讨论】:

    • 是的,这行得通。然而这是一个大类,实际上我必须在 B 中添加很多转发成员,这使得它非常混乱.. 我试图避免这种情况。
    • @ttrrxx:很遗憾,您不能使用带有不同参数的函数来覆盖函数。这恰好包括默认参数函数。如果它与您有关,您也许可以编写一个宏来为您编写转发成员。
    • 谢谢.. 由于我控制界面和实现,我愿意接受任何建议、宏、模板、仿函数或任何其他有意义的东西。我只想拥有一个最小且干净的代码库。希望有一些创造性的方式来做到这一点。
    • 不,那样不行。 void f()void f(arg) 是 2 个不同的函数签名,即使您有默认参数值。
    • @ttrrxx 这是您发布的问题的正确解决方案。但是,您似乎还有另一个问题:接口函数似乎不太适合 A 的虚拟接口的大类 B。这可能是 A 的虚拟接口过于受限或 B 的接口太大的问题,即可能违反 SRP。或者也许你应该充实一个具有f(int) 的实现类,而B 只是一个包含这样一个实现并将f() 转发到impl::f(0) 的适配器
    【解决方案2】:

    当你有一个接口时,基本原则应该是函数总是接受相同的参数并且总是以相同的方式操作,无论派生类在做什么。不允许添加额外的参数,因为这假定对对象进行操作的“事物”“知道”参数是/做什么。

    有几种方法可以解决这个问题 - 立即浮现在脑海的是:

    1. 将参数添加到接口/基类。
    2. 不要使用参数,而是使用一些额外的函数,[当创建派生对象或“知道差异”的其他地方时] 将额外信息存储在需要它的对象内。
    3. 添加另一个“知道”类内部参数的类。

    第二个例子是:

    class B: public A
    {  
       private:
         int x; 
       public:
         B() x(0) { ... }   // default is 0. 
         void f() { ... uses x ... }
         void setX(int newX) { x = newX; };
         int getX() { return x; }
    };
    

    所以,当你想使用x 与另一个值不为零时,你调用bobject->setX(42); 或类似的东西。

    【讨论】:

    • 问题是我需要强制来自接口 A 的客户端调用始终将 arg 设置为 0。如果 x 通过内部接口 B 意外设置为 1,则客户端对 f() 的访问将具有 arg设置为 1,这将是不好的。
    【解决方案3】:

    根据您的描述,我想说您应该提供两个类,它们都具有特定的职责:一个实现所需的功能,另一个为客户端提供所需的接口。这样您就可以分离关注点并且不会违反 SRP:

    class BImpl {
    public:
      doF(int arg);  
    };
    
    class B : public A {
      BImpl impl;
    public:
      virtual void f() override {
        impl.doF(0);
      }
    };
    

    【讨论】:

      【解决方案4】:

      快速进行函数转发会导致繁琐的代码重复,并且会污染 B 的内部接口。我想知道在 C++ 中处理这个问题的最佳方法是什么。

      听起来您需要编写一个脚本来自动化部分过程。

      【讨论】:

        猜你喜欢
        • 2013-09-09
        • 2014-10-01
        • 2021-11-22
        • 1970-01-01
        • 2017-08-16
        • 1970-01-01
        • 1970-01-01
        • 2016-08-17
        • 1970-01-01
        相关资源
        最近更新 更多