C++:从另一个构造函数隐式调用构造函数
C++: Implicit call of constructor from another constructor
我很难理解我正在处理的项目中的隐式构造函数调用。
有两个接口:InterfaceA和InterfaceB。
然后,有两个实现 classes:ImplementA 和 ImplementB,它们从各自的接口派生。在任何一点上都没有共同的祖先 - 尽管接口和 classes 非常相似。
第三个 class,Component,可用于初始化任何 Implement classes。
所以我们有这样的东西:
class InterfaceA
{
public:
InterfaceA(){}
virtual ~InterfaceA(){}
// Some functions
}
class InterfaceB
{
public:
InterfaceB(){}
virtual ~InterfaceB(){}
// Some functions
}
class ImplementA : public InterfaceA
{
public:
ImplementA(Component& input);
ImplementA(Component* input);
ImplementA(const ImplementA& impl);
ImplementA(const ImplementB& impl);
ImplementA();
~ImplementA(void);
private:
Component* m_component;
bool some_boolean;
}
class ImplementB : public InterfaceB
{
public:
ImplementB(Component& input);
ImplementB(const ImplementA& impl);
ImplementB(const ImplementB& impl);
ImplementB();
~ImplementB(void);
private:
Component* m_component;
}
然后,我们有一个 return 指向组件的指针的函数:
Component* foo()
{
Component* result = new Component();
...
return result;
}
最后,在代码的某处,我们有以下 return:
return new ImplementB(foo());
当运行时,上面的行执行foo(),然后执行ImplementA(Component* input),然后执行ImplementB(const ImplementA& impl) - 这让我很困惑。
1. 为什么它甚至可以编译?编译器不应该抱怨这种类型的参数没有有效的构造函数(当我在相关调用中更改某些内容时它会这样做)。顺便说一下,我使用的是 Visual Studio 2012。
2. 我知道当一个构造函数得到一个指向对象的指针作为参数时,它首先调用该参数的拷贝构造函数。所以,如果我忽略没有合适的构造函数这一事实——它不应该使用 Component 的复制构造函数而不是 ImplementA 吗? ImplementA 似乎与 ImplementB 完全没有联系(除了它们具有相似的结构)。
我错过了什么?在这种情况下可能导致此行为的原因是什么?
这就是你拥有太多、令人困惑的构造函数的结果。我也强烈怀疑你到处都有内存泄漏。
注意ImplementA
有一个构造函数ImplementA(Component&)
和一个构造函数ImplementA(Component*)
。但是 ImplementB
只有 ImplementB(Component&)
。这令人困惑。
所以当您执行 new ImplementB(foo())
时,没有直接接受 Component*
的构造函数。编译器会寻找其他选项。具体来说,它会寻找一种方法将参数 Component*
转换为 ImplementB
的某些构造函数接受的参数。
C++ 有一个叫做用户定义转换的东西。您可以定义 conversion operators 和 converting constructors 来定义类型之间新的隐式类型转换。事情是这样的:任何具有单个参数的构造函数都是转换构造函数,除非它被标记为 explicit
。 (这可能是 C++ 中的一个设计错误。但我们坚持了下来。)
因此,ImplementA(Component*)
定义了从 Component*
到 ImplementA
的隐式转换。还有 ImplementB(const ImplementA&)
构造函数可以接受 ImplementA
临时的。所以编译器使用这个构造函数,使用转换构造函数来创建临时的,最终结果就是你看到的执行。
解决方案是制作所有这些构造函数 explicit
,同时定义更少、更少混淆的构造函数。并使用智能指针来消除内存泄漏。
return new ImplementB(foo());
When run, the line above executes foo(), then executes ImplementA(Component* input), and then ImplementB(const ImplementA& impl) - which confuses me very much.
调用foo
returns一个Component*
。当我们检查 ImplementB
的构造函数时,我们发现
ImplementB(Component& input);
ImplementB(const ImplementA& impl);
ImplementB(const ImplementB& impl);
所以其中 none 个接受 Component*
。
但是 "luckily" 其中一个选项是 ImplementA
,可以 从指针构造。
和一个 "user-defined conversion"是允许传递参数的。
foo
returns一个Component*
。
ImplementB
没有接受 Component*
的构造函数。但是它有一个接受 const ImplementA&
.
的构造函数
现在 Component*
可以通过接受 Component*
的后者的构造函数 隐式转换 到 ImplementA
。因此它被转换,并且生成的 ImplementA
临时值通过 const 引用传递给 ImplementB
.
的适当构造函数
如果您重视自己的理智,您可能不希望在代码附近的任何位置进行 任何 隐式转换。要停止用户定义类型的隐式转换,请声明所有单参数构造函数 explicit
.
我很难理解我正在处理的项目中的隐式构造函数调用。
有两个接口:InterfaceA和InterfaceB。
然后,有两个实现 classes:ImplementA 和 ImplementB,它们从各自的接口派生。在任何一点上都没有共同的祖先 - 尽管接口和 classes 非常相似。
第三个 class,Component,可用于初始化任何 Implement classes。
所以我们有这样的东西:
class InterfaceA
{
public:
InterfaceA(){}
virtual ~InterfaceA(){}
// Some functions
}
class InterfaceB
{
public:
InterfaceB(){}
virtual ~InterfaceB(){}
// Some functions
}
class ImplementA : public InterfaceA
{
public:
ImplementA(Component& input);
ImplementA(Component* input);
ImplementA(const ImplementA& impl);
ImplementA(const ImplementB& impl);
ImplementA();
~ImplementA(void);
private:
Component* m_component;
bool some_boolean;
}
class ImplementB : public InterfaceB
{
public:
ImplementB(Component& input);
ImplementB(const ImplementA& impl);
ImplementB(const ImplementB& impl);
ImplementB();
~ImplementB(void);
private:
Component* m_component;
}
然后,我们有一个 return 指向组件的指针的函数:
Component* foo()
{
Component* result = new Component();
...
return result;
}
最后,在代码的某处,我们有以下 return:
return new ImplementB(foo());
当运行时,上面的行执行foo(),然后执行ImplementA(Component* input),然后执行ImplementB(const ImplementA& impl) - 这让我很困惑。
1. 为什么它甚至可以编译?编译器不应该抱怨这种类型的参数没有有效的构造函数(当我在相关调用中更改某些内容时它会这样做)。顺便说一下,我使用的是 Visual Studio 2012。
2. 我知道当一个构造函数得到一个指向对象的指针作为参数时,它首先调用该参数的拷贝构造函数。所以,如果我忽略没有合适的构造函数这一事实——它不应该使用 Component 的复制构造函数而不是 ImplementA 吗? ImplementA 似乎与 ImplementB 完全没有联系(除了它们具有相似的结构)。
我错过了什么?在这种情况下可能导致此行为的原因是什么?
这就是你拥有太多、令人困惑的构造函数的结果。我也强烈怀疑你到处都有内存泄漏。
注意ImplementA
有一个构造函数ImplementA(Component&)
和一个构造函数ImplementA(Component*)
。但是 ImplementB
只有 ImplementB(Component&)
。这令人困惑。
所以当您执行 new ImplementB(foo())
时,没有直接接受 Component*
的构造函数。编译器会寻找其他选项。具体来说,它会寻找一种方法将参数 Component*
转换为 ImplementB
的某些构造函数接受的参数。
C++ 有一个叫做用户定义转换的东西。您可以定义 conversion operators 和 converting constructors 来定义类型之间新的隐式类型转换。事情是这样的:任何具有单个参数的构造函数都是转换构造函数,除非它被标记为 explicit
。 (这可能是 C++ 中的一个设计错误。但我们坚持了下来。)
因此,ImplementA(Component*)
定义了从 Component*
到 ImplementA
的隐式转换。还有 ImplementB(const ImplementA&)
构造函数可以接受 ImplementA
临时的。所以编译器使用这个构造函数,使用转换构造函数来创建临时的,最终结果就是你看到的执行。
解决方案是制作所有这些构造函数 explicit
,同时定义更少、更少混淆的构造函数。并使用智能指针来消除内存泄漏。
return new ImplementB(foo());
When run, the line above executes foo(), then executes ImplementA(Component* input), and then ImplementB(const ImplementA& impl) - which confuses me very much.
调用foo
returns一个Component*
。当我们检查 ImplementB
的构造函数时,我们发现
ImplementB(Component& input);
ImplementB(const ImplementA& impl);
ImplementB(const ImplementB& impl);
所以其中 none 个接受 Component*
。
但是 "luckily" 其中一个选项是 ImplementA
,可以 从指针构造。
和一个 "user-defined conversion"是允许传递参数的。
foo
returns一个Component*
。
ImplementB
没有接受 Component*
的构造函数。但是它有一个接受 const ImplementA&
.
现在 Component*
可以通过接受 Component*
的后者的构造函数 隐式转换 到 ImplementA
。因此它被转换,并且生成的 ImplementA
临时值通过 const 引用传递给 ImplementB
.
如果您重视自己的理智,您可能不希望在代码附近的任何位置进行 任何 隐式转换。要停止用户定义类型的隐式转换,请声明所有单参数构造函数 explicit
.