从另一个 class 的初始化隐式调用 Class 构造函数
Implicit call of Class constructor from Initialisation of another class
以下代码片段似乎有效:
#include <iostream>
class Filling{
public:
const int num;
Filling(int num_)
: num(num_)
{ }
};
class Nougat{
public:
Nougat(const Filling& filling)
: reference(filling)
{ }
const Filling& get_filling() const{ return reference; }
private:
const Filling& reference;
};
class Wrapper{
public:
Wrapper(const Nougat& nougat)
: reference(nougat)
{ }
const Nougat& get_nougat() const{ return reference; };
private:
const Nougat& reference;
};
int main(){
Filling filling(3);
Wrapper wrap(filling); /*(0)*/
std::cout << wrap.get_nougat().get_filling().num << std::endl;
}
虽然初始化不正确(在/*(0)*/
),因为Wrapper
class应该接受一个Nougat
class,但是却给出了一个 Filling
class.
由于构造函数采用引用,我相信编译器正在从构造函数参数创建一个临时的 Nougat
class,然后将其传递给初始化 Wrapper
class.
从临时对象获取引用会导致未定义的行为。
这是真的吗?
如果是这样,这段代码如何编译?
Wrapper
的构造函数需要对 Nougat
的引用,但您给它的是 Filling
。与 C++ 中的所有函数调用一样,在这种情况下 隐式转换序列 将考虑所有参数。
隐式转换序列可以是例如从派生的 class 引用到基础 class 引用的转换,但由于 Nougat
和 Filling
不相关这样,这不适用于此处。
隐式转换序列中另一个允许的步骤是用户定义的转换。这也包括目标类型的所谓 转换构造函数 ,即未标记 explicit
的构造函数。构造函数 Nougat(const Filling& filling)
就是这种情况,它允许从 Filling
转换为 Nougat
。
因此,可以调用此构造函数构造一个Nougat
类型的临时对象作为隐式转换。生成的临时文件也可以绑定到 const
左值引用。
为避免此类无意的转换,您应该将构造函数标记为 explicit
,至少如果它们只接受一个参数,除非您确实有意进行此类隐式转换。
在 wrapper
的构造结束时,临时对象被销毁,因此在
中获得了引用
wrap.get_nougat()
悬空,使用后会导致未定义的行为。
以下代码片段似乎有效:
#include <iostream>
class Filling{
public:
const int num;
Filling(int num_)
: num(num_)
{ }
};
class Nougat{
public:
Nougat(const Filling& filling)
: reference(filling)
{ }
const Filling& get_filling() const{ return reference; }
private:
const Filling& reference;
};
class Wrapper{
public:
Wrapper(const Nougat& nougat)
: reference(nougat)
{ }
const Nougat& get_nougat() const{ return reference; };
private:
const Nougat& reference;
};
int main(){
Filling filling(3);
Wrapper wrap(filling); /*(0)*/
std::cout << wrap.get_nougat().get_filling().num << std::endl;
}
虽然初始化不正确(在/*(0)*/
),因为Wrapper
class应该接受一个Nougat
class,但是却给出了一个 Filling
class.
由于构造函数采用引用,我相信编译器正在从构造函数参数创建一个临时的 Nougat
class,然后将其传递给初始化 Wrapper
class.
从临时对象获取引用会导致未定义的行为。
这是真的吗?
如果是这样,这段代码如何编译?
Wrapper
的构造函数需要对 Nougat
的引用,但您给它的是 Filling
。与 C++ 中的所有函数调用一样,在这种情况下 隐式转换序列 将考虑所有参数。
隐式转换序列可以是例如从派生的 class 引用到基础 class 引用的转换,但由于 Nougat
和 Filling
不相关这样,这不适用于此处。
隐式转换序列中另一个允许的步骤是用户定义的转换。这也包括目标类型的所谓 转换构造函数 ,即未标记 explicit
的构造函数。构造函数 Nougat(const Filling& filling)
就是这种情况,它允许从 Filling
转换为 Nougat
。
因此,可以调用此构造函数构造一个Nougat
类型的临时对象作为隐式转换。生成的临时文件也可以绑定到 const
左值引用。
为避免此类无意的转换,您应该将构造函数标记为 explicit
,至少如果它们只接受一个参数,除非您确实有意进行此类隐式转换。
在 wrapper
的构造结束时,临时对象被销毁,因此在
wrap.get_nougat()
悬空,使用后会导致未定义的行为。