Question

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?

Was it helpful?

Solution

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.

OTHER TIPS

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

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top