Как этого добиться? - PullRequest
       22

Как этого добиться?

1 голос
/ 23 ноября 2010

Упрощено: потому что способ, которым проблема была представлена ​​раньше, вводил в заблуждение.Виноват.Кроме того, чтобы не тратить время людей на полную трату :) :::

Yh

#ifndef Y_H
#define Y_H

#include <iostream>

class X;
class Y
{
    private:
        friend class X;
        void Print()
        {
            std::cout << "Y::Print" << std::endl;
        }
};

#endif

Xh

#ifndef X_H
#define X_H

#include "Y.h"

class X
{
    public:
        void Something(Y* pY)
        {
            pY->Print();
        }
};          

#endif

Это несколько отличается от моей первоначальной проблемы.Я прошу прощения за все проблемы :).Уверяю вас, это возможно.

Правила: не меняйте Yh или Xh Получите X::Something, чтобы сделать что-то другое, чем то, что он делает сейчас.

Это пришло ко мне, когда ядумал о этом.

Ответы [ 8 ]

3 голосов
/ 24 ноября 2010

Это невозможно.

На данный момент:

pRoot->Evaluate();

Компилятор уже знает, что будет вызывать Node::Evaluate, потому что он не виртуален.Вы сказали, что не можете редактировать эту реализацию, поэтому теперь вы знаете, что единственный путь - изменить реализацию Node::Evaluate.

, что, как вы сказали, вы также не можете сделать.Вот и все, вы не можете.


Я бы порекомендовал вам прекратить биться вокруг куста и задать реальный вопрос.Скажите: «Это библиотека, которую я использую, это то, как я ее использую, вот что происходит, но вот что я хочу сделать. Как?»Или даже расширить область действия до «Вот проблема, которую я решаю, и решить ее ...», чтобы разрешить совершенно разные подходы.

Но задавать эти «загадочные» вопросы с плохо определенными параметрами и целямиглупо.Так что не надо.

1 голос
/ 24 ноября 2010

Правила: не меняйте Y.h или X.h. Получите X :: Что-то, чтобы сделать что-то кроме того, что он делает сейчас.

Хорошо.

#include "Y.h"
class Hack {
public:
  static void Print();
};

#define Y Hack
#include "X.h"
#undef Y

void Hack::Print() {
  std::cout << "Something else" << std::endl;
}

int main() {
  Hack y;
  X().Something(&y);
  return 0;
}

Конечно, это не изменит поведение любых существующих единиц перевода, которые уже используют Something, потому что вы не можете.

Кроме того, если вы попробуете то же самое без ключевого слова static, убедитесь, что классы Hack и Y совместимы с макетом.

1 голос
/ 24 ноября 2010

Легко. Никогда не включайте X.h (ваша проблема никогда не указывает, что он должен быть включен в какие-либо единицы перевода) и переопределяйте класс X внутри другого заголовка. Проблема решения.

Редактировать: Вы также можете сделать что-то действительно зло, как

#define void virtual void
#include "X.h"

, а затем наследовать, или

#define X X_impl

и напишите свой новый класс X.

1 голос
/ 24 ноября 2010

Найдите адрес функции оценки и перезапишите первую инструкцию в ней с помощью JMP для собственной, которая оценивает представление Node, определенное реализацией.

1 голос
/ 23 ноября 2010

Обобщаемого решения не существует, потому что Evaluate вполне мог быть встроен в Execute.

1 голос
/ 23 ноября 2010

Если это возможно и не так уж и сложно, я бы предпочел получить и отредактировать источник, который определяет class Node, сделать Evaluate виртуальным, а затем перекомпилировать все необходимое.Конечно, это совсем не хак.

Если исходный код недоступен или создание его библиотеки будет огромной проблемой, я мог бы (в Linux) попытаться использовать общий объект LD_PRELOAD, содержащий только(искалеченный) символ Node::Evaluate().

0 голосов
/ 24 ноября 2010

Если вы можете изменить синтаксический анализатор, создайте новую функцию EvaluateNode и поместите туда свой новый метод.

Вам придется заменить все вызовы Evaluate на EvaluateNode.Это не будет работать, если вы полагаетесь на вызовы Evaluate в коде, который вы не можете изменить.

Другой способ - создать другой класс узла, скажем, ModifiableNode, который имеет частный узел и реализует все его функциональные возможности с помощьювызов методов Node, кроме метода Evaluate.Затем замените Node на ModifiableNode в Parser.

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

0 голосов
/ 23 ноября 2010

Пусть класс скажет, MyNode происходит от Node класса. Предоставьте приватный виртуальный метод скажем EvaluateImpl() для узла и для новых классов MyNode. Измените метод Node::Evaluate() для вызова нового частного виртуального метода EvaluateImpl(). Переместите существующую функциональность Node::Evaluate() в новый метод Node::EvaluateImpl(). Поместите вашу новую функциональность в MyNode::EvaluateImpl()
Затем передайте объект производного класса в метод Parser::Execute().

class Node
{
     private:
         friend class Parser;
         void Evaluate() { EvaluateImpl(); }
         virtual void EvaluateImpl(); //Move functionality  from Evaluate() to here
};

class MyNode
{
     private:
         virtual void EvaluateImpl(); //Implement your new functionality.
};
...