CRTP变量inizializatin中的衍生类
考虑以下实现CRTP的代码,
#include <iostream>
template <typename T>
class base {
int n;
base() {}
friend T;
public:
explicit base(int _n) : n{_n} {}
void print() const { static_cast<const T&>(*this).whoami(); }
};
class derived : public base<derived> {
public:
void whoami() const { std::cout << n << std::endl; }
};
int main()
{
base<derived> a{6};
a.print();
}
如预期,代码打印6。
默认的构造函数base :: base()
将离开成员字段n
非专业化。但是,由于它是private
和base
是friend
derived
,因此只有derived
使用base :: base()
(具体来说,在其编译器生成的默认文件中)。但是派生
没有公共构造函数,因此永远不会实例化。因此,从n
的初始化点起,代码似乎是安全的,尽管代码的一部分实际上没有执行正确的初始化。
所以我想知道:上面的代码中是否有陷阱?
注意
请注意,它不仅仅是学术的问题。在现实情况下,base
的成员可能没有明智的默认初始化,并且由base
的构造函数初始化,该构建器采用一系列参数。这些参数只能在运行时确定,并在main()
中用于实例base&lt; derived&gt;
。
class base {
public:
base(int param1, char *param2);
};
如果base
没有默认构造函数,则需要一个派生
的构造函数,该构建器调用base类base&lt; derived&gt;
的构造函数。如果没有明智的默认参数,则将其称为 “随机”参数
class derived : public base<derived> {
derived() : base<derived>(42, "unexisting_file") { }
};
Consider the following code implementing CRTP
#include <iostream>
template <typename T>
class base {
int n;
base() {}
friend T;
public:
explicit base(int _n) : n{_n} {}
void print() const { static_cast<const T&>(*this).whoami(); }
};
class derived : public base<derived> {
public:
void whoami() const { std::cout << n << std::endl; }
};
int main()
{
base<derived> a{6};
a.print();
}
The code prints 6 as expected.
The default constructor base::base()
would leave the member field n
uninitialized. However, since it is private
and base
is friend
to derived
, only derived
uses base::base()
(specifically, in its compiler-generated default contructor). But derived
has not public constructors, so it is never instantiated. So the code seems to be safe from the point of the initialization of n
, though there is a part of the code that, effectively, does not perform the correct initialization.
So I wonder: is there a pitfall in a code like above?
Note
Please notice that the question it not merely academic. In a real-world case, the members of base
may not have a sensible default initialization, and are initialized by a constructor of base
that takes a series of parameters. These parameters can be possibly determined at runtime only, and used in main()
to instantiate base<derived>
.
class base {
public:
base(int param1, char *param2);
};
If there is no default constructor for base
, you need a constructor for derived
that calls the constructor of the base class base<derived>
. When this has no sensible default parameters, it would be very awkward to call it with
"random" parameters
class derived : public base<derived> {
derived() : base<derived>(42, "unexisting_file") { }
};
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论