WedX - журнал о программировании и компьютерных науках

Как наследовать и реализовать чистый виртуальный метод с абстрактным классом в качестве параметра?

У меня есть абстрактный класс Node, который содержит чистый виртуальный метод-заглушку matches, требующий в качестве параметра еще один экземпляр Node (т. е. экземпляр чего-то, что является подклассом Node).

class Node; // forward declaration

class Node {
public:
    Node() : parentNode(this) {}
    virtual ~Node() {}

    Node* parentNode;

    virtual bool matches(const Node& node) const = 0;
};

Как я могу реализовать matches в подклассе, чтобы параметр мог иметь тип подклассов, а не Node?

Например. Я хочу, чтобы что-то вроде следующего зарегистрировалось как реализованная версия контракта из Node, чтобы я мог получить доступ к определенным свойствам NodeImpl как часть функции, которую я иначе не смог бы сделать:

class NodeImpl : public Node {
private:
    int foo;
    ...
};

...

bool NodeImpl::matches(const NodeImpl& n) const {
    return this->foo == n.foo;
}

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

Что я пробовал:

template <class T>
class Node;

template <class T>
class Node {
public:
    Node() : parentNode(this) {}
    virtual ~Node() {}

    Node* parentNode;

    virtual bool matches(const T& node) const = 0;
};

Чтобы я мог вызывать совпадения в шаблонной функции следующим образом:

template <class T>
void pathComp(Node<T>& currNode, Node<T>& rootNode) {
    Node<T> *node = &currNode;
    while (node->matches(rootNode)) {
        ...
    }
}

Я не мог заставить этот метод работать, к тому же мне не нравилось, что мне, казалось бы, нужно было иметь class NodeImpl : public Node<NodeImpl> в качестве наследства, что-то в этом казалось не совсем правильным. Любой совет относительно того, был ли я на правильных линиях или нет, был бы замечательным!


  • Что касается шаблона, я считаю, что вы хотите bool matches(const Node<T> &node) const, и он не должен быть виртуальным. 15.03.2014
  • Конструкция NodeImpl : public Node<NodeImpl> является известным паттерном, как бы странно это ни выглядело. Ознакомьтесь с странно повторяющимся шаблоном. 15.03.2014

Ответы:


1

В общем, вы не можете этого сделать, потому что это не будет безопасным для типов. Например:

struct Node { virtual bool matches(const Node &) const = 0; }
struct NodeA : Node { virtual bool matches(const NodeA &) const; };
struct NodeB : Node { virtual bool matches(const NodeB &) const; };

NodeA a; // compiler doesn't allow, but if it did...
NodeB b;
Node &c = a;
c.matches(b); // oops!

То, как вы говорите о его реализации, предполагает, что b имеет тот же тип, что и a, но у компилятора нет возможности проверить это предположение в целом, поэтому он этого не допустит.

Однако, если вы используете два узла одного типа, вы всегда можете сделать так, чтобы функция matches() не была виртуальной:

struct Node {   }
struct NodeA : Node {  bool matches(const NodeA &) const; };

NodeA a1;
NodeA a2;
a1.matches(a2); // fine
15.03.2014
  • Итак, если бы я хотел, чтобы Node по контракту обязал подклассы реализовать метод matches, но только между Node подклассами одного и того же типа, как бы я это сделал? Я пробовал использовать шаблоны и иметь bool matches(const T& node), но при этом немного запутался. 15.03.2014
  • @Quetzalcoatl: Не могли бы вы привести пример того, как это можно использовать? 15.03.2014
  • Конечно, дайте мне минуту или две, чтобы расширить мой вопрос. 15.03.2014
  • @Quetzalcoatl: то, о чем вы просите, в принципе невозможно во время компиляции. matches() должен принимать общий Node в качестве входных данных, а затем каждый класс должен будет использовать dynamic_cast, чтобы проверить, является ли ввод правильным типом, прежде чем что-то с ним делать, например: bool A::matches(const Node &node) const { const A *a = dynamic_cast<const A*>(&node); if (a) { ... } else return false; } 15.03.2014

  • 2

    Вы должны уважать подписание контракта суперкласса. Затем, если вам нужно получить доступ к свойствам подкласса, просто приведите к подклассу по мере необходимости.

    15.03.2014
    Новые материалы

    Объяснение документов 02: BERT
    BERT представил двухступенчатую структуру обучения: предварительное обучение и тонкая настройка. Во время предварительного обучения модель обучается на неразмеченных данных с помощью..

    Как проанализировать работу вашего классификатора?
    Не всегда просто знать, какие показатели использовать С развитием глубокого обучения все больше и больше людей учатся обучать свой первый классификатор. Но как только вы закончите..

    Работа с цепями Маркова, часть 4 (Машинное обучение)
    Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

    Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
    Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..

    Использование машинного обучения и Python для классификации 1000 сезонов новичков MLB Hitter
    Чему может научиться машина, глядя на сезоны новичков 1000 игроков MLB? Это то, что исследует это приложение. В этом процессе мы будем использовать неконтролируемое обучение, чтобы..

    Учебные заметки: создание моего первого пакета Node.js
    Это мои обучающие заметки, когда я научился создавать свой самый первый пакет Node.js, распространяемый через npm. Оглавление Глоссарий I. Новый пакет 1.1 советы по инициализации..

    Забудьте о Matplotlib: улучшите визуализацию данных с помощью умопомрачительных функций Seaborn!
    Примечание. Эта запись в блоге предполагает базовое знакомство с Python и концепциями анализа данных. Привет, энтузиасты данных! Добро пожаловать в мой блог, где я расскажу о невероятных..


    Для любых предложений по сайту: [email protected]