0

Consider the following base class, which will count how many times I call CallDerivedFunction:

class B {
  public:
    B() {numCalls = 0;}
    void CallDerivedFunction() {numCalls++; DerivedFunction();}
    int GetNumCalls() {return numCalls;}
  private:
    virtual void DerivedFunction() = 0;
    int numCalls;
};

People other than me will be writing derived classes that implement DerivedFunction. However, I'm trying to count how many times DerivedFunction gets called.

Is there any way prevent a derived class D from directly calling its own implementation of DerivedFunction, eg. disallow:

class D : public B {
  private:
    void DerivedFunction() {
      if(<some condition>) DerivedFunction(); // I don't want to allow this.
      if(<some condition>) CallDerivedFunction(); // This is OK.
    }
};

Note: OK, of course this is a simplification; the more general question is, when my base class is supposed to be functioning as a manager and doing things like tracking usage patterns, etc for a collection of derived classes, can I force the derived classes to call through the manager class? Or must I rely on derived-class developers to do the right thing here?

  • If `DerivedFunction` is a member function written by the user, even if you prevent him to call it directly, he can copy the function body and create a new member function with the same content of `DerivedFunction` and call it. I don't see reasons for doing such a thing. – Murilo Vasconcelos Jun 20 '12 at 20:24
  • By the way, D::DerivedFunction calls itself infinitely -> stack overflow. Even if you call B::CallDerivedFunction, you will land right back into D::DerivedFunction -> stack overflow. So your example is completely broken. – Julien Lebot Jun 20 '12 at 20:27
  • @LeSnip3R: I apologize, I was just trying to keep the example minimal. is meant to stand in for some condition that prevents this. A more complete example could include a static variable that ensures the function only calls itself one time in ten, or something like that. I can edit the example if necessary. – Clayton Davis Jun 20 '12 at 21:06

2 Answers2

4

Yes, you can do this - I believe this is called the pass-key idiom.

You add a "key" helper class to your base-class that only the base class can instantiate (i.e. ctor is private, but friend of the base-class), but that the derived class can see. Then you add a reference to this helper class to the signature of the function you wish to "lock" so that only the base-class may call it - since it is the only class that can instantiate the "key".

class A
{
   public:
     class Key {Key(); friend ::A;};
     // Only A can call this, since only A can instantiate A::Key
     virtual void Foo(A::Key&)=0; 
};


class B:public A
{
  public:
    virtual void Foo(A::Key&) override
    {
      // B can override this...
    }

    void Bar()
    {
      Key k; // <- this wont compile, so you cannot call Foo from B
      this->Foo(k);
    }
};

Note that this doesn't prevent recursion like in your example. But you could probably get that to work by using a value instead of a reference and disabling the copy constructor of the key.

ltjax
  • 15,837
  • 3
  • 39
  • 62
0

how would you call DerivedFunction in class D if that function is Private ? which means you can only call CallDerivedFunction from class B

Nir
  • 356
  • 1
  • 5
  • His program is valid, if he tried B::DerivedFunction then the compiler would complain, but because he defines D::DerivedFunction it works just fine; although his code is recursive on all path -> stack overflow at runtime but that's beside the point. – Julien Lebot Jun 20 '12 at 20:25
  • I didn't say that his program is invalid,I was just saying that his derive class doesn't expose the function he wants to prevent from calling and therefore, it is prevented from being called out side of the B class – Nir Jun 20 '12 at 20:31
  • That's incorrect, his derived class does define DerivedFunction, which he wants to prevent from being called, thus D can call it. The problem is not who can call from outside the class, but who can call from inside the class. – Julien Lebot Jun 20 '12 at 20:36
  • ...and this should be a comment. – Mahmoud Al-Qudsi Jun 20 '12 at 20:39
  • well the way I understood his question is not if B can call it or not because it seems that is what he wants, but how to prevent from outside to call it and therefore the private on the function will prevent from outside to call that function, and therefore only B class will be able to call it or D itself, but why would you want to call your a function in a class where you try to prevent from calling. – Nir Jun 20 '12 at 21:03