Возврат значения из шаблона посетителя

У меня есть иерархия следующим образом:

         class Element{ public : virtual void Accept(Visitor&) = 0
protected : Element();   int num;
};

class ElementA : public Element{
public : ElementA();
void Accept(Visitor& v) {v.Visit(this};}
};

class ElementB : public Element{
public : ElementB();
void Accept(Visitor& v) {v.Visit(this};}class Visitor{
public: void Visit(ElementA*);
void Visit(ElementB*);
};

РЕДАКТИРОВАТЬ:
Требуется добавить метод int getNum () в иерархию, которая предоставит значение num. Однако для этого потребуется снова скомпилировать всю иерархию, и нам не разрешено это делать. Таким образом, мы должны изменить дизайн иерархии таким образом, чтобы перекомпиляция иерархии не требовалась.

3

Решение

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

int Visitor::getNum(Element* pe)
{
//define a pick-pocket... ;)
struct ElementNumAccessor : private Element
{
ElementNumAccessor(Element const& e) : Element(e) {}
int getNum() { return num; }

void Accept(Visitor&); //has to be declared, but needs not be defined
};

//...and let him work:
ElementNumAccessor ea(*pe);
return ea.getNum();
}

Эта душа в действии: http://ideone.com/e1chSX
Это использует тот факт, что защищенный доступ является транзитивным, но за счет копии каждого элемента, из которого вы хотите получить число. Я сделал структуру локальным классом функции, так что никто не может даже использовать ее для каких-либо других целей.

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

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

3

Другие решения

Одна возможность состоит в том, чтобы объявить GetNumVisitor как друг Element class и получить доступ к num переменная-член напрямую. Затем добавьте метод в GetNumVisitor вернуть значение.

class Element {
...
friend GetNumVisitor;  // declare GetNumVisitor as a friend class
...
};

GetNumVisitor : public Visitor {
private:
int  m_numelement;
public :
void visit(Element *E) { m_elementNum = E->num; }
int getNum() const { return m_elementNum;}
};

Вы должны будете назвать это как

 ElementA element_a();
ElementB element_b();
GetNumVisitor getnumVisitor();
element_a.accept(getnumVisitor);
int a = getnumVisitor.getNum();
element_b.accept(getNumVisitor);
int b = getnumVisitor.getNum();
...
0

Не эксперт по шаблону посетителя, но соответствует ли это вашим требованиям?

    class Element{ public : virtual void Accept(Visitor&) = 0
protected : Element();   int num;
};

class ElementA : public Element{
public : ElementA();
void Accept(Visitor& v) {v.setNum(this->num); v.Visit(this);}
};

class ElementB : public Element{
public : ElementB();
void Accept(Visitor& v) {v.setNum(this->num); v.Visit(this);}class Visitor{
public:
void Visit(ElementA*);
void Visit(ElementB*);
void setNum(int _num) {num = _num;}
int getNum() {return num;}

private:
int num;
};
0

Ваш вопрос, как разрешить класс (Visitor) для прямого доступа к частному члену данных, унаследованному в другой иерархии классов (Elementс).

Быстрый ответ будет: не надо! это сломает всю цель модификаторов видимости.
Однако делать это все еще возможно с помощью friend (приводит к перекомпиляции иерархии) или с помощью реинтерпретации указателей.

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

0
По вопросам рекламы [email protected]