3

I am currently trying to make sure that a member function of one class is only called by a member function of another class.

The architecture is imposed and cannot be changed, the port means that some logic has to be done in a.call() before calling b.call(). a.call() therefore calls b.call() to simplify things and make sure the order is respected.

I found this answer to my question. Only, the problem is that I am using classes, and the two classes have the same member function name and so the #define tries to replace all the occurrences which have different prototypes.

Community
  • 1
  • 1
3nixios
  • 357
  • 2
  • 12

5 Answers5

7

I recommend the passkey pattern. It's very good for giving fine grained control on who can do what with your function.

Community
  • 1
  • 1
Xeo
  • 129,499
  • 52
  • 291
  • 397
  • This is actually really cool. I wouldn't have thought of that. – Björn Pollex Jul 01 '11 at 08:54
  • @Xeo: oh that's a nice name, we struggled some a year ago and nobody would know its name, I like yours :) – Matthieu M. Jul 01 '11 at 09:01
  • @Space: I love that pattern (esp. C++0x version) and I try to spread the word whenever I can. :) – Xeo Jul 01 '11 at 09:02
  • @Matthieu: If you go through that question's OP's questions, there should be one asking for a name (or one of the related questions has it), and that was the accepted answer. :) **Edit**: [Here it is](http://stackoverflow.com/questions/3324248/how-to-name-this-key-oriented-access-protection-pattern). – Xeo Jul 01 '11 at 09:04
  • @Xeo: yes, but dropping the friend is a nice move :) The struggle I referred to was the precise question you linked :) – Matthieu M. Jul 01 '11 at 11:45
3

Off the top of my head, options would be:

  • Make b.call private and make b add a or a.call as a friend
  • Turn b.call into a class and put the body into a a private constructor with a or a.call as a friend
  • grep the source code for b.call, make sure the only call is in a.call, and add a comment at the declaration saying "if you call this function you will be fired"
  • Change b.call to take at least one of the values it needs as a parameter (even if it ignores it and uses the value from somewhere else)
MSalters
  • 173,980
  • 10
  • 155
  • 350
Jack V.
  • 1,381
  • 6
  • 20
  • Yeah the first option is what I did in the end. I'll delete my answer and accept yours. – 3nixios Jul 01 '11 at 08:43
  • @3nixios: Note though, that now *every* function in `a` can call `b.call()`. – Xeo Jul 01 '11 at 08:45
  • @Xeo I agree that this could be problematic, but it leaves much less scope for erroneously calling `b.call`, although my question was specific, this should be good enough for me. Thanks. – 3nixios Jul 01 '11 at 08:52
1

Can you change b.call to take a reference to a? This way, b.call can call a.call itself:

struct A {
    void call() {
        // do stuff
    }
};

struct B {
    void call(A & a) {
        a.call();
        // do stuff
    }
};

This makes sure that a.call is always called before the rest of b.call is executed.

Björn Pollex
  • 75,346
  • 28
  • 201
  • 283
  • +1 Yes this would be nice to keep the dependency, but by preference I find using a _friend_ class 'cleaner'. – 3nixios Jul 01 '11 at 08:47
  • @3nixios: They are cleaner, but the way you stated your problem, they don't exactly solve it. Any method of the friend can call the method, so you still have the possibility of calling in the wrong order. – Björn Pollex Jul 01 '11 at 08:50
  • @Space_C0wb0y This is true, but for my specific useage this is good enough for the moment. Your answer is more globally acceptable, which is why I still upvoted. – 3nixios Jul 01 '11 at 08:53
0

How about using a flag?

a.call()
{
    // ...
    flag = 1;
    b.call();
    flag = 0;
}

b.call()
{
    if (flag == 0)
        return;

    // ...
}
Donotalo
  • 12,748
  • 25
  • 83
  • 121
  • This would require a shared flag between the two classes, which I don't find vto be much to my taste. Also the compile-time check provided by the friend-class is much more appropriate. – 3nixios Jul 01 '11 at 08:48
0

If you program for certain platform (say x86 or x64), and you know the calling convention (e.g. cdecl), then you can get this info from the stack

Say you want to check the object that called the function, so use the this pointer that is pushed to the stack prior to calling the member function: get the this pointer and compare it with the object that you want (this_pointer == a)

If you want to check certain function, get the caller address from the stack and check against that function: caller_address == A::call. If it's a virtual function, use the this pointer to get the vtable.

Depending on the calling-convention and the order of pushing variables on the stack, you may have to check first the input variables sizes, in order to get to the information you need.

Tar
  • 8,529
  • 9
  • 56
  • 127