无法使用成为好友的CRTP类的私有构造函数

时间:2019-03-27 18:09:07

标签: c++ friend crtp

我有使用此设计的代码,简化了此MCVE的工作-代码和编译器错误随之出现。

基本问题是我认为与CRTP类成为朋友将允许模板化基类访问派生的CRTP类的私有成员,包括其私有构造函数。

但是显然不是。为什么?

this code on wandbox

#include <iostream>
using namespace std;

template <class CRTP>
class Base
{
  friend CRTP;
public:
  static void Factory()
  {
      cout << "Base::Factory()" << endl;
      CRTP x;
      x.Hello();
  }
  virtual void Hello() { cout << "Base::Hello()" << endl; }
protected:
  Base() { cout << "Base::Base()" << endl; }
  virtual ~Base() { cout << "Base::~Base()" << endl; }
};


class Derived final : public Base<Derived>
{
public:
  void Hello() override;
private:
  Derived() { cout << "Derived::Derived()" << endl; }
  ~Derived() override { cout << "Derived::~Derived()" << endl; }
};

int main()
{
    Derived::Factory();
    // Expected output:
    //   Base::Factory()
    //   Base::Base()
    //   Derived::Derived()
    //   Derived::Hello()
    //   Derived::~Derived()
    //   Base::~Base()
}

并收到此编译器错误(从clang 9.0.0,但gcc抱怨的方式相同):

prog.cc:12:12: error: calling a private constructor of class 'Derived'
      CRTP x;
           ^
prog.cc:33:14: note: in instantiation of member function 'Base<Derived>::Factory' requested here
    Derived::Factory();
             ^
prog.cc:27:3: note: declared private here
  Derived() { cout << "Derived::Derived()" << endl; }
  ^
prog.cc:12:12: error: variable of type 'Derived' has private destructor
      CRTP x;
           ^
prog.cc:28:11: note: declared private here
  virtual ~Derived() { cout << "Derived::~Derived()" << endl; }
          ^
2 errors generated.

(仅供参考:用例是我希望模板基类通过静态工厂控制(CRTP)派生类实例的生存期-包括构造-因此,我希望派生类将其构造函数声明为私有的,但可以访问父级的静态工厂方法。此示例显示了在堆栈上创建的派生类实例,但如果在堆中创建(并返回),则会发生相同的错误。

2 个答案:

答案 0 :(得分:2)

您在错误的类中得到了friend声明。 Derived需要声明Base<Derived>为朋友,因为朋友可以访问私人成员。 (一个类将另一个类声明为朋友。一个类并不将自身声明为另一个类的朋友。)

您要添加

friend Base<Derived>;

放入Derived类声明中。

答案 1 :(得分:2)

您要提到的具体问题是将friend声明放在Base中而不是Derived中。

下一个问题是Derived::Hello()没有实现。如果不需要(如上面的示例),则仅在Base中实现它,然后删除virtual声明。 Derived仍将继承它。

以下作品:

#include <iostream>

using namespace std;

template <class CRTP>
class Base
{
 public:
  static void Factory()
  {
    cout << "Base::Factory()" << endl;
    CRTP x;
    x.Hello();
  }
  void Hello() { cout << "Base::Hello()" << endl; }

 protected:
  Base() { cout << "Base::Base()" << endl; }
  virtual ~Base() { cout << "Base::~Base()" << endl; }
};

class Derived final : public Base<Derived>
{
  friend Base<Derived>;
/*^^^^^^ friend declaration goes here, not in Base */

  Derived() { cout << "Derived::Derived()" << endl; }
  ~Derived() override { cout << "Derived::~Derived()" << endl; }
}; 

输出:

Base::Factory()
Base::Base()
Derived::Derived()
Base::Hello()
Derived::~Derived()
Base::~Base()