CRTP:将基类的访问限制为派生类的某些成员

CRTP: restrict access of Base class to some members of Derived class

提问人:francesco 提问时间:11/17/2023 更新时间:11/17/2023 访问量:78

问:

考虑 CRTP 模式。我想:template <class DerivedType> class Base

  1. 无法实例化基类

  2. 派生类中的(某些)方法只能通过基类的“接口”调用

  3. 基类只能访问 Derived 的某些私有成员

要满足 1.,声明 Base 类的构造函数就足够了。为了满足 2.,可以将方法设为私有,并声明 Base 类。但是,这将允许 Base 访问 Derived 的所有成员。protectedfriend

例如,请参阅以下代码:

#include <iostream>

template <class T>
class Base {
protected:
  Base() = default;

public:
  void interface() const { static_cast<const T*>(this)->do_something(); }

  // This should not compile
  void interface_to_private() const { static_cast<const T*>(this)->do_something_private(); }
};

class Derived : public Base<Derived> {
  friend class Base<Derived>;
  void do_something() const { do_something_private(); }
  // These should be not available to Base<Derived>
  int i = 1;
  void do_something_private() const { std::cout << "hello " << i << std::endl; }
};

int main()
{
  Derived d;
  d.interface();
  d.interface_to_private(); // This should give error

  return 0;
}

在示例代码中,我希望能够访问 ,但不能访问 ,也不能访问 成员字段。Base<Derived>do_something()do_something_private()int i

我知道访问的粒度是一个已知的问题,例如,可以通过律师-客户习语来解决。但是,我无法弄清楚它是否真的可以与 CRTP 成语相结合。不言而喻,我不想要虚拟成员(这是使用 CRTP 的全部意义所在)。friend

我通过将方法隐藏在另一个类中找到了解决方案:

#include <iostream>

template <class T>
class Base {
protected:
  Base() = default;

public:
  void interface() const { static_cast<const T*>(this)->do_something(); }
  // This should not compile
  void interface_to_private() const { static_cast<const T*>(this)->do_something_private(); }

};

class Implementation {
  int i = 1;
  void do_something_private() const { std::cout << "hello " << i << std::endl; }

protected:
  Implementation() = default;
  
public:
  void do_something() const { do_something_private(); }
};

class Derived : public Base<Derived>, private Implementation {
  friend class Base<Derived>;
};

int main()
{
  Derived d;
  d.interface();
  // uncommenting gives compile error
  // d.interface_to_private();

  return 0;
}

取消注释该行会导致编译错误。d.interface_to_private();

虽然这似乎有效,但它似乎涉及,我想知道这是否是一个很好的解决方案,因为多重继承通常不受欢迎

在这种情况下,有没有更好的解决方案,或者一个已知的“成语”?

C++ 友元 crtp

评论

0赞 Oersted 11/17/2023
客户/律师模式。AKA钥匙/钥匙圈
1赞 Oersted 11/17/2023
@Fareanor:在CRTP中,基座可以调用子成员函数吗?这难道不是用子作为模板参数实例化基的目的吗?
1赞 Swift - Friday Pie 11/17/2023
@Fareanor CRTP 实际上是两种不同模式C++实现 - 您描述的 mixin 和类中的函数多态性(它是一种静态类型的多态性)。在 C++23 中,后者可以通过推导此功能来实现,而不会出现类型不完整的先有鸡还是先有蛋的问题。
1赞 Jarod42 11/17/2023
“例如,这可以通过律师-客户习语来解决。” Passkey Idiom 是另一种选择。
1赞 Oersted 11/17/2023
@Fareanor当我部分专用化模板类时,我通常使用 CRTP。我将通用实现放在基类中,如果它需要从基成员函数调用某个方法,其实现随专业化而变化,则使其成为 CRTP。我一直认为 CRTP 是实现这一目标的好设计。

答: 暂无答案