怎么做到这一点?

时间:2010-11-23 20:30:07

标签: c++ puzzle

简化:因为之前出现问题的方式具有误导性。我的错。也不要让人们的时间完全浪费:) :::

Y.h

#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

X.h

#ifndef X_H
#define X_H

#include "Y.h"

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

#endif

这与我原来的问题有些不同。我为所有的麻烦道歉:)。我向你保证,这是可能的。

规则: 不要更改Y.h或X.h. 让X::Something做一些不同于现在的事情。

当我在考虑this.

时,这就出现了

8 个答案:

答案 0 :(得分:3)

这是不可能的。

此时:

pRoot->Evaluate();

编译器已经知道它将调用Node::Evaluate,因为它是非虚拟的。您已经说过无法编辑此实现,所以现在您知道要采取的唯一方法是修改Node::Evaluate的实现。

你说的你也做不到。所以就是这样,你做不到。


我建议你不要在丛林周围殴打并提出一个真正的问题。说“这是我正在使用的库,这就是我使用它的方式,这是正在发生的事情,但这就是我想要发生的事情。怎么样?”或者甚至将范围扩大到“这是我正在解决的问题,并解决它......”以允许完全不同的方法。

但是用不明确的参数和目标来问这些“谜题”问题是愚蠢的。所以不要。

答案 1 :(得分:1)

如果可能而且不是很大的痛苦,我宁愿获取并编辑定义class Node的源,使Evaluate成为虚拟,然后重新编译所需的一切。当然,这根本不是黑客攻击。

如果源代码不可用或构建其库将是一个巨大的痛苦,我可能(在Linux上)尝试使用仅包含(受损)符号LD_PRELOAD的{​​{1}}共享对象。 / p>

答案 2 :(得分:1)

没有一般化的解决方案,因为评估可能已被内联到执行中。

答案 3 :(得分:1)

找到evaluate函数的地址,并用自己的JMP重写其中的第一条指令,它评估Node的实现定义表示。

答案 4 :(得分:1)

易。永远不要包含X.h(您的问题永远不会指定它应该包含在任何翻译单元中)并在另一个标题内重新定义类X.问题解决方案。

编辑:你也可以做一些非常邪恶的事情,比如

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

然后继承,或

#define X X_impl

并编写自己的新X类。

答案 5 :(得分:1)

  

规则:不要更改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关键字的情况下尝试相同的操作,请确保类HackY与布局兼容。

答案 6 :(得分:0)

让一个班级MyNode来自Node班级。提供一个私有虚拟方法,说明EvaluateImpl()到Node和新的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.
};

答案 7 :(得分:0)

如果您可以修改解析器,请创建一个新函数EvaluateNode并将新方法放在那里。

您必须使用EvaluateNode替换所有要评估的调用。如果您依赖于无法修改的代码中的Evaluate调用,则无效。

另一种方法是创建另一个节点类,比如ModifiableNode,它有一个私有节点,并通过调用Node方法实现它的所有功能,但Evaluate方法除外。然后在Parser中将Node替换为ModifiableNode。

如果你不能修改Parser,那么你将不得不做像aschepler建议的那样并创建一个新函数,然后以某种方式欺骗链接器提供你的函数而不是库的。我不知道该怎么做,对我来说听起来真是个坏主意。