不能使用好友 CRTP 的私有构造函数 class
Can't use private constructor of befriended CRTP class
我有使用此设计的代码,经过简化以获得此 MCVE - 代码和编译器错误如下。
基本问题是,我认为与 CRTP class 交朋友将允许模板化基础 class 访问派生的 CRTP class 的私有成员,包括其私有构造函数。
但显然不是。为什么?
#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.
(仅供参考:用例是我希望模板库 class 通过静态工厂控制(CRTP)派生 class 实例的生命周期 - 包括构造。所以我想要派生classes 将它们的构造函数声明为私有的,但父类的静态工厂方法可以访问。此示例显示了在堆栈上创建的派生 class 实例,但如果它是在堆中创建的(和返回)。)
您的 friend
声明有误 class。 Derived
需要声明 Base<Derived>
为好友,因为好友可以访问私有成员。 (A class 声明另一个 class 为朋友。A class 没有声明自己为另一个 class 的朋友。)
您要添加
friend Base<Derived>;
进入Derived
class声明。
您提到的具体问题是您将 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()
我有使用此设计的代码,经过简化以获得此 MCVE - 代码和编译器错误如下。
基本问题是,我认为与 CRTP class 交朋友将允许模板化基础 class 访问派生的 CRTP class 的私有成员,包括其私有构造函数。
但显然不是。为什么?
#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.
(仅供参考:用例是我希望模板库 class 通过静态工厂控制(CRTP)派生 class 实例的生命周期 - 包括构造。所以我想要派生classes 将它们的构造函数声明为私有的,但父类的静态工厂方法可以访问。此示例显示了在堆栈上创建的派生 class 实例,但如果它是在堆中创建的(和返回)。)
您的 friend
声明有误 class。 Derived
需要声明 Base<Derived>
为好友,因为好友可以访问私有成员。 (A class 声明另一个 class 为朋友。A class 没有声明自己为另一个 class 的朋友。)
您要添加
friend Base<Derived>;
进入Derived
class声明。
您提到的具体问题是您将 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()