Возможно ли иметь виртуальный тип в C ++? - PullRequest
1 голос
/ 15 января 2020

У меня есть класс MyClass (с несколькими виртуальными функциями), который выполняет операции над объектом с именем MyType.

Класс MyClassImpl наследует MyClass и реализует виртуальные функции, но мне нужно добавить дополнительные члены к MyType, но я не хочу изменять класс MyType (вместо этого я хочу чтобы сделать его обобщенным c).

Теперь, если я сделаю MyTypeImpl и унаследую MyType, я могу добавить членов. Но как я могу заставить не виртуальные функции в MyClassImpl (унаследованные от MyClass) использовать новый MyTypeImpl?

Единственный способ, которым я могу думать, - это заставить MyClass использовать MyTypeImpl, но я хочу избежать использования реализации в классе generi c, потому что я мог бы использовать различные различные реализации.

Вот простой пример того, как могут выглядеть классы. Конечно, код не будет компилироваться, потому что методы и члены добавлены в MyTypeImpl, а не MyType.

class MyType {
  public:
    void increment() {
      data_++;
    }
  protected:
    int data_ = 0;
};

class MyClass {
  public:   
    void alg() {
      sub_routine_1();
      sub_routine_2();
      modify_mytype();
    };

  protected:
    MyType mytype_;

    virtual void sub_routine_1() = 0;
    virtual void sub_routine_2() = 0;

    void modify_mytype() {
      mytype_.increment();
    };
};

class MyTypeImpl : public MyType {
  public:
    void decrement() {
      data_--;
      is_decremented = true;
    };

  protected:
    bool is_decremented = false;;
};

class MyClassImpl : public MyClass{
  public:
    void print() {
      mytype_.print();
    };
  protected:
    virtual void sub_routine_1() {
      //do algorithm things here
      mytype_.increment();
      mytype_.increment();
    };
    virtual void sub_routine_2() {
      //do more algorithm things here
      mytype_.decrement();
      mytype_.decrement();
    };
};

1 Ответ

3 голосов
/ 15 января 2020

После просмотра вашего примера я вижу, что вы просто хотите расширить функциональность этого класса без изменения исходного класса. Если вам нужно добавить дополнительные функции, но вы не хотите изменять тип, который хранится в MyClass, я не знаю, как это сделать, по крайней мере, изменив MyType для включения виртуальных функций для функции, которые вы хотите вызвать.

Вам также нужно заставить MyClass взять указатель на MyType, чтобы вы могли использовать полиморфизм и разрешить вызовы в правильной реализации:

Dynami c Полиморфизм Решение:

#include <iostream>

class MyType {
  public:
    virtual void increment() {
      data_++;
    }

    // To be implemented by implementation class
    virtual void print() = 0;

    // To be implemented by implementation class
    virtual void decrement() = 0;

  protected:
    int data_ = 0;
};

class MyTypeImpl : public MyType
{
public:
    void print() {
        std::cout << 42 << std::endl;
    }

    void decrement() {
        data_--;
        is_decremented = true;
    };

protected:
    bool is_decremented = false;;
};

class MyClass {
  public:
    MyClass(MyType* mytype)
        : mytype_(mytype)
    {}

    void alg() {
      sub_routine_1();
      sub_routine_2();
      modify_mytype();
    };

  protected:
    MyType* mytype_;

    virtual void sub_routine_1() = 0;
    virtual void sub_routine_2() = 0;

    void modify_mytype() {
      mytype_->increment();
    };
};

class MyClassImpl : public MyClass{
  public:
    MyClassImpl(MyType* mytype)
        : MyClass(mytype)
    {}

    void print() {
      mytype_->print();
    };
  protected:
    virtual void sub_routine_1() {
      //do algorithm things here
      mytype_->increment();
      mytype_->increment();
    };
    virtual void sub_routine_2() {
      //do more algorithm things here
      mytype_->decrement();
      mytype_->decrement();
    };
};

int main()
{
    MyType* mytype = new MyTypeImpl();
    MyClass* myclass = new MyClassImpl(mytype);

    // Prints "42"
    myclass->print();

    // Do other stuff with "myclass"

    delete myclass;
    delete mytype;
}

Обратите внимание, в этом примере я использую только необработанный указатель для большей ясности. Настоятельно рекомендуется не использовать new и delete и использовать интеллектуальные указатели для управления временем жизни ваших указателей.

Stati c Полиморфизм Решение:

Не то, чтобы дизайн этого решения был на самом деле лучше, но я думаю, что это ближе к тому, что вы на самом деле ищете, потому что не требует непосредственного изменения класса MyType. Также единственное изменение, необходимое для MyClass, - сделать его классом шаблона:

#include <iostream>

class MyType {
  public:
    virtual void increment() {
      data_++;
    }

  protected:
    int data_ = 0;
};

class MyTypeImpl : public MyType
{
public:
    void print() {
        std::cout << data_ << std::endl;
    }

    void decrement() {
        data_--;
        is_decremented = true;
    };

protected:
    bool is_decremented = false;
};

template <typename T>
class MyClass {
  public:

    void alg() {
      sub_routine_1();
      sub_routine_2();
      modify_mytype();
    };

  protected:
    T mytype_;

    virtual void sub_routine_1() = 0;
    virtual void sub_routine_2() = 0;

    void modify_mytype() {
      mytype_.increment();
    };
};

template <typename T>
class MyClassImpl : public MyClass<T> {
  public:
    void print() {
      this->mytype_.print();
    };

  protected:
    virtual void sub_routine_1() {
      //do algorithm things here
        this->mytype_.increment();
        this->mytype_.increment();
    };
    virtual void sub_routine_2() {
      //do more algorithm things here
        this->mytype_.decrement();
        this->mytype_.decrement();
    };
};

int main()
{
    // Use the template to get the correct implementation
    MyClassImpl<MyTypeImpl> myclass;

    myclass.alg();
    myclass.print();

    // Do other stuff with my class
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...