Удалить дублирование кода для членов виртуального класса в наследовании C ++ - PullRequest
0 голосов
/ 21 октября 2018

У меня возникла странная проблема сейчас.Я напишу действительно упрощенную версию того же самого.

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.
}

Теперь проблема ... и der1, и der2 реализуют виртуальные функции базы практически одинаково.Но некоторые другие классы (der3, der4) имеют свои собственные реализации.Но все же надо наследовать от базы.Как мне выполнить рефакторинг кода, чтобы удалить дублирование кода oop способом?

Ответы [ 3 ]

0 голосов
/ 21 октября 2018

Идея с 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();
};
0 голосов
/ 21 октября 2018

Вот одно решение, использующее промежуточный слой другого абстрактного базового класса:

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
        }
    };
    
0 голосов
/ 21 октября 2018

Вариант 1

Вы можете рассмотреть возможность использования своей наиболее распространенной реализации в классе Base.Главной особенностью или недостатком этого метода является то, что базовый класс больше не будет абстрактным.Если это проблема, перейдите к варианту 2.

Возможно, вы даже сможете справиться с различиями в производных классах, используя шаблон метода шаблона для извлечения различийв защищенных виртуальных функциях, вызываемых методом шаблона.

В любом случае, для производных классов, которые требуют совершенно другого подхода, вы просто переопределяете метод Base class '.

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.

Переопределение чисто виртуальной функции будет тогда просто вызывать защищенную базовую классную общую функцию (для der1 и der2) или просто использовать их собственную реализацию, которая полностью отличается (для der3 и der4).

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 будет более подходящим.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...