简化:因为之前出现问题的方式具有误导性。我的错。也不要让人们的时间完全浪费:) :::
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.
时,这就出现了答案 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
关键字的情况下尝试相同的操作,请确保类Hack
和Y
与布局兼容。
答案 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建议的那样并创建一个新函数,然后以某种方式欺骗链接器提供你的函数而不是库的。我不知道该怎么做,对我来说听起来真是个坏主意。