代码之家  ›  专栏  ›  技术社区  ›  nakiya

如何做到这一点?

  •  1
  • nakiya  · 技术社区  · 14 年前

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

    小精灵

    #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 回复  |  直到 14 年前
        1
  •  3
  •   GManNickG    14 年前

    这是不可能的。

    此时:

    pRoot->Evaluate();
    

    编译器已经知道它将调用 Node::Evaluate 因为它不是虚拟的。您已经说过不能编辑此实现,所以现在您知道唯一的方法是修改 节点::评估 .

    你说你也做不到。就这样,你不能。


    我建议你别绕着树丛转了,问一个真正的问题。说“这是我正在使用的库,这是我使用它的方式,这是正在发生的事情,但这是我想要发生的事情。怎么样?”或者甚至把范围扩大到“这是我要解决的问题,并解决它…”,以允许完全不同的方法。

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

        2
  •  1
  •   aschepler    14 年前

    如果可能的话,并且不是一个巨大的痛苦,我更愿意获取和编辑定义 class Node 制作 Evaluate 虚拟,然后重新编译所需的一切。当然,这根本不是黑客。

    如果源代码不可用或构建它的库将是一个巨大的痛苦,我可能(在Linux上)尝试使用 LD_PRELOAD 仅包含(损坏)符号的共享对象 Node::Evaluate()

        3
  •  1
  •   Alex Brown    14 年前

    没有可归纳的解决方案,因为Evaluate可能已经内联到了执行中。

        4
  •  1
  •   Edward Strange    14 年前

    找到evaluate函数的地址,并使用JMP将其中的第一条指令重写为您自己的指令,这将评估节点的实现定义的表示。

        5
  •  1
  •   Puppy    14 年前

    容易的。永远不要包含x.h(您的问题从来没有指定它应该包含在任何翻译单元中),并且在另一个头中重新定义类x。问题解决。

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

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

    然后继承,或者

    #define X X_impl
    

    写你自己的新的x类。

        6
  •  1
  •   aschepler    14 年前

    规则:不要更改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 布局是否兼容。

        7
  •  0
  •   riderchap    14 年前

    让全班同学说 MyNode 派生自 Node 类。提供一个私有的虚拟方法 EvaluateImpl() 节点和新节点 MyNoad 课程。修改 Node::Evaluate() 调用新私有虚拟方法的方法 EvaluateImpl()。 . 移动的现有功能 节点::评估() 到新的 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.
    };
    
        8
  •  0
  •   Dominique McDonnell    14 年前

    如果您可以修改解析器,那么就创建一个新的函数evaluateNode,并将新方法放在其中。

    您必须用EvaluateNode替换所有要计算的调用。如果您依赖调用来在无法修改的代码中进行计算,那么这将不起作用。

    另一种方法是创建另一个节点类,比如modifiablenode,它有一个私有节点,并通过调用节点方法实现它的所有功能,evaluate方法除外。然后在解析器中将节点替换为可修改的节点。

    如果您不能修改解析器,那么您必须执行Aschepler建议的操作,并创建一个新的函数,然后以某种方式欺骗链接器提供您的函数而不是库的函数。我不知道如何执行此操作,对我来说这听起来是一个非常糟糕的主意。