Нужен способ обхода виртуального шаблона
Мне нужно написать программу, реализующую шаблон дизайна посетителя. Проблема в том, что базовый класс посетителя является классом шаблона. Это означает, что BaseVisited:: accept() принимает класс шаблона в качестве параметра, и поскольку он использует 'this', и мне нужно 'this', чтобы указать на правильный экземпляр среды выполнения объекта, он также должен быть виртуальным.
Я хотел бы знать, есть ли способ решить эту проблему.
template <typename T>
class BaseVisitor {
public:
BaseVisitor();
T visit(BaseVisited *visited);
virtual ~BaseVisitor();
}
class BaseVisited {
BaseVisited();
template <typename T>
virtual void accept(BaseVisitor<T> *visitor) { visitor->visit(this); }; // problem
virtual ~BaseVisited();
}
Ответы
Ответ 1
Что вам нужно сделать, это разделить BaseVisitor.
class BaseVisited;
class BaseVisitorInternal {
public:
virtual void visit(BaseVisited*) = 0;
virtual ~BaseVisitorInternal() {}
};
class BaseVisited {
BaseVisited();
virtual void accept(BaseVisitorInternal* visitor) { visitor->visit(this); }
};
template<typename T> class BaseVisitor : public BaseVisitorInternal {
void visit(BaseVisited* visited);
};
Если вам нужны базовые классы BaseVisited для шаблонов и передайте их правильные типы/перегрузки для посещения, вы официально мертвы.
Ответ 2
Я придумал что-то немного отличное от DeadMG:
class BaseVisited;
class IVisitor {
public:
virtual void visit(BaseVisited *visited) = 0;
virtual ~IVisitor();
};
template <typename T>
class BaseVisitor : public IVisitor {
public:
BaseVisitor();
virtual void visit(BaseVisited *visited);
virtual ~BaseVisitor();
virtual T result();
};
class BaseVisited {
public:
BaseVisited();
virtual void accept(IVisitor *visitor) { visitor->visit(this); };
virtual ~BaseVisited();
};
Mine имеет дополнительную функцию члена result()
, которая позволяет получить результат последнего посещения.
Ответ 3
Вы не можете объявлять/определять шаблонные виртуальные функции. Причина в том, что механизм виртуальной отправки должен быть известен, когда компилятор видит определение базового класса, но шаблоны компилируются по требованию.
При использовании общей реализации vtable проблема заключается в том, что количество записей, которые компилятор должен зарезервировать для виртуальной функции, это undefined (сколько может быть разных типов экземпляров типа?), равно как и порядок их. Если вы объявите класс:
class base {
public:
virtual void foo();
virtual int bar();
};
Компилятор может зарезервировать две записи в таблице vtable для указателей на foo
и bar
в таблице vtable, а таблица vtable отлично определена, просто проверив определение класса. Это не может быть достигнуто с помощью шаблонных функций.