在没有朋友的情况下为基类提供受保护的访问权限

Give protected access to base class without friend

本文关键字:受保护 访问 权限 访问权 朋友 情况下 基类      更新时间:2023-10-16

我将首先解释我的情况。

我有一个基类,可以自动实现一种引用计数。 它允许我将 C 样式的init()free()库调用包装到引用计数的 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;

希望实现这些初始值设定项和终止符的类将从如下所示Service派生:

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

但是,声明很混乱,因为我必须继承和交朋友我的Service类。 有没有办法允许基类自动访问派生类的受保护成员或私有成员? 如果没有,我不妨问一下是否有更好的方法来写我在这里所做的。

"有没有办法允许基类自动访问派生类的受保护成员或私有成员?"

基类无法正式访问派生类的私有/受保护成员。通常,基类的设计方式是它们不需要知道派生类的任何内容。因此,如果需要从基类访问派生类中的成员,则应重新考虑设计。

编辑(根据@RSahu提议的文章):-

尽管在某些情况下,从基类访问派生类的成员函数可能很有用。就像在两个进程之间共享对象一样。

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

N.M. 将这些方法虚拟化的建议让我想到:它本身不会工作,但如果将服务与其管理分离,它会起作用:初始化不仅适用于该特定服务实例,它适用于所有实例,也许正因为如此,它首先不应该成为服务类的一部分。

如果将它们解耦,则可以使用派生服务管理器必须实现的虚拟方法创建服务管理器基类,如下所示:

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

如果您的编译器不支持这种&&的使用(它有效C++11,但无效C++03),您仍然应该能够通过进行s_manager ServiceManager &而不使用临时T来初始化它,或者只是使s_manager具有类型 T 来轻松调整代码。前者更详细,后者允许T不是从ServiceManager派生的实现。