nakiya
nakiya

Reputation: 14423

How to achieve this?

Simplified: Because the way the problem was presented before was misleading. My mistake. Also not to make peoples' time a complete waste :) :::

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

This is somewhat different from my original problem. I apologize for all the trouble :). I assure you, this IS possible.

Rules: Don't change Y.h or X.h. Get X::Something to do something other than what it is doing now.

This came to me when I was thinking about this.

Upvotes: 1

Views: 189

Answers (8)

aschepler
aschepler

Reputation: 72473

Rules: Don't change Y.h or X.h. Get X::Something to do something other than what it is doing now.

Okay.

#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;
}

Of course, this won't change the behavior of any existing translation units which already use Something, because you can't.

Also, if you try the same thing without the static keyword, make sure classes Hack and Y are layout-compatible.

Upvotes: 1

Puppy
Puppy

Reputation: 147036

Easy. Never include X.h (your problem never specifies that it should be included in any translation units) and redefine class X inside another header. Problemo solvo.

Edit: You could also do something REALLY evil like

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

and then inherit, or

#define X X_impl

and write your own new X class.

Upvotes: 1

Edward Strange
Edward Strange

Reputation: 40897

Find the address of the evaluate function and rewrite the first instruction in it with a JMP to your own, which evaluates the implementation defined representation of Node.

Upvotes: 1

GManNickG
GManNickG

Reputation: 504303

It's impossible.

At this point:

pRoot->Evaluate();

The compiler already knows it'll be calling Node::Evaluate, because it's non-virtual. You've said you cannot edit this implementation, so now you know the only path to take is to modify the implementation of Node::Evaluate.

Which you said you also cannot do. So that's it, you can't.


I'd recommend you stop beating around the bush and ask a real question. Say "this is the library I'm using, this is how I'm using it, here's what's happening, but here's what I want to happen. How?" Or even expand the scope to "Here's the problem I'm solving, and to solve it..." to allow completely different approaches.

But asking these "puzzle" questions with ill-defined parameters and goals is silly. So don't.

Upvotes: 3

Dominique McDonnell
Dominique McDonnell

Reputation: 2520

If you can modify the parser make a new function EvaluateNode and put your new method in there.

You will have to replace all calls to Evaluate with EvaluateNode. This wouldn't work if you are relying on calls to Evaluate in code you can't modify.

Another way is to create another node class, say ModifiableNode which has a private node and implements all of it's functionality by calling Node methods, except for the Evaluate method. Then replace Node with ModifiableNode in Parser.

If you can't modify Parser, then you'll have to do something like aschepler suggested and create a new function and then somehow trick the linker into supplying your function instead of the library's. I have no idea how to do this, and sounds like a really bad idea to me.

Upvotes: 0

riderchap
riderchap

Reputation: 687

Have a class say MyNode derive from Node class. Provide a private virtual method say EvaluateImpl() to Node and to the new MyNode classes. Modify the Node::Evaluate() method to call the new private virtual method EvaluateImpl(). Move the existing functionality of Node::Evaluate() to the new Node::EvaluateImpl() method. Put your new functionality to MyNode::EvaluateImpl()
Then pass the derived class object to Parser::Execute() method.

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.
};

Upvotes: 0

Alex Brown
Alex Brown

Reputation: 42932

There's no generalizable solution, because Evaluate may well have been inlined into Execute.

Upvotes: 1

aschepler
aschepler

Reputation: 72473

If possible and not a huge pain, I would prefer to get and edit the source which defines class Node, make Evaluate virtual, and then recompile everything needed. Of course, this is not a hack at all.

If the source code is not available or building its library would be a huge pain, I might (on Linux) attempt using an LD_PRELOAD shared object containing only the (mangled) symbol Node::Evaluate().

Upvotes: 1

Related Questions