Переопределение чистой виртуальной функции из шаблонных классов

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

У меня есть интерфейс, который я назову BaseInterface, который определяет функции, которые я хотел бы переопределить во всех классах, производных от этого интерфейса. В этом примере, скажем, есть только одна чистая виртуальная функция с именем toImplement. Я создаю класс под названием Base, который наследуется от BaseInterface и добавляет некоторые функциональные возможности унаследованным чистым виртуальным функциям. Base по-прежнему является абстрактным классом, поскольку он не реализует функции BaseInterface.

У меня есть несколько классов, которые являются производными от Base, все они используют общие функции Base, но указывают, что происходит, когда toImplement запускается на их экземплярах. Все эти классы должны быть конкретными и удовлетворять всем требованиям, установленным BaseInterface. Ниже я определяю один из этих классов под названием Производные.

Все это отлично работает, когда BaseInterface и Base не созданы. Код компилируется и отлично работает без определения (1.) или реализации (2.) toImplement в Base.

Однако я бы хотел, чтобы toImplement работал с разными типами. Насколько я понимаю, иметь чистые виртуальные функции в шаблонном классе - это нормально. Я использую шаблон BaseInterface и Base для некоторого типа T. Когда я не определяю toImplement в Base (1. ), Я не могу скомпилировать, поскольку Base не знает, какой toImplement использовать в tryUsingImplemented. Если я сейчас добавлю определение в Base, код будет предварительно компилироваться, но компоновщик не сможет найти реализацию Base :: toImplement. Наконец, если я и определяю, и реализую toImplement в Base (1. и 2.), код компилируется.

Мне это не нравится, потому что у меня есть фиктивная реализация toImplement в Base, и я никогда не хочу, чтобы эта реализация запускалась. Кроме того, поскольку Base реализует toImplement, Derived больше не требуется для его реализации. Это делает BaseInterface бесполезным в моих глазах.

Может ли кто-нибудь просветить меня о том, как принудительно реализовать реализацию toImplement в Derived без необходимости сначала реализовать его в Base, если это вообще возможно ?

template <typename T>
class BaseInterface {
   virtual void toImplement(T & t) = 0;
};


template <typename T>
class Base : public BaseInterface<T> {
bool m_useImplemented;

public:
   explicit Base(bool useImplemented) : m_usedImplemented(useImplemented) {}

   void tryUsingImplemented(T & t) {
      if (m_useImplemented)
         toImplement(t);
   }  

protected:
   // 1: Defining toImplement pure virtual function in Base
   virtual void toImplement(T & t);
};

// 2. Implementing a version of toImplement in Base which does nothing
template <typename T>
inline void Base<T>::toImplement(T & t) {
   // do nothing
}

class Derived : public Base<int> {
public:
   explicit Derived(bool useImplemented) : Base<int>(useImplemented) {}

protected:
   // 3. implementing toImplement in Derived 
   void toImplement(T & t) {
      std::cout << "Doing stuff for Derived" << std::endl;
   }  

};

person user3293204    schedule 10.02.2014    source источник
comment
Вы можете предоставить определения для чистых виртуальных функций. Если вы не хотите, чтобы производные классы выполняли невиртуальный вызов Base::toImplement, сделайте его частной функцией.   -  person Simple    schedule 10.02.2014
comment
Я попытался максимально упростить мою задачу и действительно забыл определить BaseInterface ‹T› :: toImplement как защищенный. Это было в исходном коде, поэтому проблема не в доступе   -  person user3293204    schedule 10.02.2014


Ответы (2)


Для дальнейшего использования было бы полезно, если бы вы предоставили сообщение об ошибке компилятора.

Однако в этом случае я знаю. В вашем коде есть две ошибки:

  1. toImplement является частным в BaseInterface.
  2. Поиск в tryUsingImplemented не будет выполняться в базовом классе. Вы столкнулись с поиском в зависимых базах проблема. Чтобы исправить, напишите this->toImplement(t).
person Sebastian Redl    schedule 10.02.2014
comment
Спасибо за ответ. Я считаю, что проблема действительно заключалась в поиске в зависимых базах. Я удалил определения и реализации чистых виртуальных машин в Base и заменил их вызовы на: this- ›toImplement, и теперь компилятор знает, как использовать BaseInterface ‹T› :: toImplement - person user3293204; 10.02.2014

Вам нужно объявить toImplement как protected в BaseInterface, если вы собираетесь вызывать его из производного класса. Я удалил все методы переопределения из производных классов и заменил тип параметра Derived::toImplement на int, и он отлично компилируется. Последнее необходимо, потому что Derived не является шаблоном, поэтому вам нужно использовать параметр шаблона, переданный в Base.

  #include <iostream>

  template <typename T>
  class BaseInterface {
  protected:
     virtual void toImplement(T & t) = 0;
  };


  template <typename T>
  class Base : public BaseInterface<T> {
  bool m_useImplemented;

  public:
     explicit Base(bool useImplemented) : m_useImplemented(useImplemented) {}

     void tryUsingImplemented(T & t) {
        if (m_useImplemented)
           toImplement(t);
     }  
  };

  class Derived : public Base<int> {
  public:
     explicit Derived(bool useImplemented) : Base<int>(useImplemented) {}

  protected:
     // 3. implementing toImplement in Derived 
     void toImplement(int & t) {
        std::cout << "Doing stuff for Derived" << std::endl;
     }  

  };
person Kristian Duske    schedule 10.02.2014
comment
Спасибо за Ваш ответ! Я забыл добавить ключевое слово protected в BaseInterface, но оно есть в моем исходном коде, так что проблема не в этом. Проблема заключалась в вызове toImplement в Base, в котором компилятор не знал, что toImplement зависит от шаблона T. Это исправляется с помощью this- ›toImplement - person user3293204; 10.02.2014
comment
Хм, компилировалось у меня без проблем с лязгом. Но все же хорошо знать об этой проблеме. - person Kristian Duske; 10.02.2014