【问题标题】:Remove code duplication for virtual class members in C++ inheritance删除 C++ 继承中虚拟类成员的代码重复
【发布时间】:2019-03-25 14:40:03
【问题描述】:

我现在陷入了一个奇怪的问题。我会写一个非常简化的版本。

class Base
{
public:
  virtual int func1()=0;
  virtual int func2()=0;
protected:
  int n;
};

class der1: public Base
{
  // implements the virtual functions of the base and uses the protected data 
  // members of the base.
};

class der2: public Base
{
  // implements the virtual functions of the base and uses the protected data 
  // members of the base.
}

现在问题....der1der2 都以几乎相同的方式实现 base 的虚函数。但是其他一些类(der3der4)有自己的实现。但仍然需要从基础继承。 如何重构代码,以 oop 的方式去除重复代码?

【问题讨论】:

  • 可以在基类中提供常用代码作为受保护的成员函数。
  • 您可以从Base12 派生Der1Der2,而Base12 本身派生自Base
  • 正如我所说,只有两个类有共同的代码,而其他一些类有不同的公共代码集。因此,没有通用代码可以满足所有这 4 个类的需求。同样,将来可能会有更多的类继承这个基类。因此,真的不想打扰基类。
  • @lifeOfPi 那么@Evg 的提议可能是要走的路。
  • 您也可以保留Base12 抽象,不需要实例化这些...无论如何,我更倾向于πάντα ῥεῖ 解决方案 - 如果有共同点,请定义它在Base 中,然后在Der3Der4 中覆盖此实现。不需要再增加一层抽象。

标签: c++ inheritance refactoring protected code-duplication


【解决方案1】:

选项 1

您可以考虑在Base 类中使用您最常用的实现。这种方法的主要特点或缺点是基类不再是抽象的。如果这是一个问题,请转到选项 2。

也许您甚至可以通过使用 template method pattern 提取模板方法调用的受保护虚函数中的差异来处理派生类中的差异。

无论如何,对于需要完全不同方法的派生类,您只需覆盖基类的方法。

class Base
{
public:
  virtual int func1();
  virtual int func2()=0;
protected:
  virtual void f1_specific_part1()=0;
  virtual void f1_specific_part2()=0; 
  int n;
};
int Base::func1() { // common skeleton of the algorithm
     ...  
     f1_specific_part1(); 
     ... 
     f1_specific_part2(); 
     ...
}     

class Der1: public Base
{ 
protected:
 void f1_specific_part1() override;  // Implements the specific variation
 virtual void f1_specific_part2() override;       
};

选项 2

您可以考虑将派生类的公共代码分解为Base 类的受保护方法。

纯虚函数的重写将只调用基类受保护的公共函数(对于der1der2)或者只使用它们自己的完全不同的实现(对于der3der4) .

class Base
{
public:
  virtual int func1()=0;
  virtual int func2()=0;
protected:
  int common_part1_funct1(); // implements some common parts 
  int common_part2_funct1();
  int n;
};

class Der1: public Base
{
...
  int func1() override { 
     common_part1_funct1();
     ...
     common_part2_funct1(); 
     ... 
  }
};

选项 3 ?

重要说明:我的回答假设大多数派生类之间存在许多共性。但是,如果您只有一小部分具有某些共性的派生类,那么Evg 的答案会更合适。

【讨论】:

    【解决方案2】:

    Base12 的想法是:

    struct Base {
        virtual int func1() = 0;
        virtual int func2() = 0;
    };
    
    struct Base12 : Base {
    protected:
        int func12();
    };
    
    struct Der1: public Base12 {
        virtual int func1() {
            return func12();
        virtual int func2() {
            return func12();
    };
    
    struct Der2: public Base12 {
        virtual int func1() {
            return func12();
        virtual int func2() {
            return func12();
    };
    

    【讨论】:

      【解决方案3】:

      这是一个使用另一个抽象基类的中间层的解决方案:

      class Base12 : public Base {
      protected: 
          int commonFuncStuffA() {
             // Commonly used stuff 
          }
      
          int commonFuncStuffB() {
          }
      };
      
      class der1: public Base12
      {
      public:
          virtual int func1() {
              n = commonFuncStuffA();
          }
          virtual int func2() {
              n = somethingElse;
          }
      };
      
      class der2: public Base12
      {
      public:
          virtual int func1() {
              n = commonFuncStuffA();
          }
          virtual int func2() {
              n = commonFuncStuffB();
          }
      };
      

      不过,我为真正的生产代码设计所做的工作看起来有点不同。

      1. 为纯虚函数声明一个接口

        struct IMyInterface {
            virtual int func1() = 0;
            virtual int func2() = 0;
            virtual ~IMyInterface {}
        };
        
      2. 提供具有常用数据成员和函数的抽象基类

        class BaseImpl : public IMyInterface {
        protected: 
            int n;
            int commonFuncStuffA() {
                // Commonly used stuff 
            }
        
            int commonFuncStuffB() {
                // Commonly used stuff 
            }
        };
        
      3. 在最终派生类中提供接口的实现

        class der1: public BaseImpl {
        public:
            virtual int func1() {
                n = commonFuncStuffA();
            }
            virtual int func2() {
                n = somethingElse;
            }
        };
        
        
        class der2: public BaseImpl {
        public:
            virtual int func1() {
                n = commonFuncStuffA();
            }
            virtual int func2() {
                n = commonFuncStuffB();
            }
        };
        
        class der3: public IMyInterface {
        public:
            virtual int func1() {
                // Some completely different implementation of the interface
            }
            virtual int func2() {
                // Some completely different implementation of the interface
            }
        };
        
        class der4: public IMyInterface {
        public:
            virtual int func1() {
                // Some completely different implementation of the interface
            }
            virtual int func2() {
                // Some completely different implementation of the interface
            }
        };
        

      【讨论】:

      • 哈哈,,,这是一个错字......但它解决了我的问题......谢谢你的帮助
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-07-13
      • 2020-10-19
      • 1970-01-01
      • 1970-01-01
      • 2012-09-27
      • 1970-01-01
      • 2017-03-31
      相关资源
      最近更新 更多