jmegaffin
jmegaffin

Reputation: 1172

Give protected access to base class without friend

I'll start by explaining my situation.

I have a base class that automatically implements a type of reference counting. It allows me to wrap C-style init() and free() library calls into a reference-counted API.

template<typename T>
class Service {
public:
    Service() {
        if(s_count++ == 0) {
            T::initialize();
        }
    }

    ~Service() {
        if(--s_count == 0) {
            T::terminate();
        }
    }

private:
    static int s_count;
};

template<typename T>
int Service<T>::s_count = 0;

Classes that wish to implement these initializers and terminators will derive from Service like so:

class Test : public Service<Test> {
    friend class Service<Test>;

private:
    static void initialize() {
        std::cout << "Initialized" << std::endl;
    }

    static void terminate() {
        std::cout << "Terminated" << std::endl;
    }
};

However, the declaration is messy since I have to both inherit from and friend my Service class. Is there any way to allow a base class access to protected or private members of a derived class automatically? If not, I may as well ask if there's any better way to write what I've done here.

Upvotes: 0

Views: 329

Answers (3)

user743382
user743382

Reputation:

n.m.'s suggestion of making these methods virtual made me think: it would not work by itself, but it would work if you decouple the service from its management: the initialization doesn't just applies to that particular service instance, it applies to all instances, and perhaps because of that it just shouldn't be part of the service class in the first place.

If you decouple them, you can make a service manager base class, with virtual methods that a derived service manager must implement, like so:

#include <iostream>

class ServiceManager {
  template <typename T>
  friend class Service;
  virtual void initialize() = 0;
  virtual void terminate() = 0;
};

template <typename T>
class Service {
public:
  Service() {
    if (s_count++ == 0) {
      s_manager.initialize();
    }
  }
  ~Service() {
    if (--s_count == 0) {
      s_manager.terminate();
    }
  }

private:
  static int s_count;
  static ServiceManager &&s_manager;
};

template <typename T>
int Service<T>::s_count = 0;

template <typename T>
ServiceManager &&Service<T>::s_manager = T();

class TestManager : public ServiceManager {
  void initialize() {
    std::cout << "Initialized" << std::endl;
  }
  void terminate() {
    std::cout << "Terminated" << std::endl;
  }
};

class Test : public Service<TestManager> {
};

If your compiler doesn't support this use of && (it's valid C++11, but not valid C++03), you should still be able to easily adapt the code by either making s_manager ServiceManager & and not using a temporary T to initialise it, or just making s_manager have type T. The former is more verbose, the latter allows T implementations that do not derive from ServiceManager.

Upvotes: 0

n. m. could be an AI
n. m. could be an AI

Reputation: 119877

#include <iostream>
using namespace std;

template<typename T>
class Service {
    struct TT: T {
      using T::initialize;
      using T::terminate;
    };
public:
    Service() {
        if(s_count++ == 0) {
            TT::initialize();
        }
    }

    ~Service() {
        if(--s_count == 0) {
            TT::terminate();
        }
    }

private:
    static int s_count;
};


class Test : public Service<Test> {
    //friend class Service<Test>;

protected:
    static void initialize() {
        std::cout << "Initialized" << std::endl;
    }

    static void terminate() {
        std::cout << "Terminated" << std::endl;
    }
};

template<typename T>
int Service<T>::s_count = 0;


int main() {   
    Test t;
}

Upvotes: 0

ravi
ravi

Reputation: 10733

"Is there any way to allow a base class access to protected or private members of a derived class automatically?"

Base class cannot access private/protected members of derived class formally. In general base classes are designed such a way that they don't need to know anything of derived class. So, if there is a need to access members in derived class from your base class then you should re-consider your design.

EDIT ( As per proposed article by @RSahu ):-

Although there are some scenario where it might be useful to access member functions of derived class from base class. Like when you are sharing objects between two processes.

Upvotes: 1

Related Questions