I'm having a hard time understanding implicit constructor calls in a project I'm working on.
There are two interfaces: InterfaceA and InterfaceB.
Then, there are two implementation classes: ImplementA and ImplementB, which are derived from the respective interface. There is no mutual ancestor in any point - even though the interfaces and classes are very much alike.
A third class, Component, can be used to initialize any of the Implement classes.
So we have something like this:
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;
}
Then, we have a function that returns a pointer to Component:
Component* foo()
{
Component* result = new Component();
...
return result;
}
And finally, somewhere in the code, we have the following return:
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.
1. Why does it even compile? Shouldn't the compiler complain that there is no valid constructor for this type of argument (which it does when I change something in the call in question). I'm using Visual Studio 2012, by the way.
2. I know that when a constructor gets a pointer to an object as an argument, it first calls the copy constructor of the argument. So, if I ignore the fact that there's no fitting constructor - shouldn't it use the copy constructor of Component instead of ImplementA? ImplementA seems to have absolutely no connection to ImplementB (aside from them having a similar structure).
What am I missing? What could be causing this behavior in this situation?
This is what you get for having too many, confusing constructors. I also strongly suspect that you have memory leaks all over the place.
Note that ImplementA
has a constructor ImplementA(Component&)
and a constructor ImplementA(Component*)
. But ImplementB
has only ImplementB(Component&)
. This is confusing.
So when you do new ImplementB(foo())
, there's no constructor that accepts a Component*
directly. The compiler goes looking for other options. Specifically, it goes looking for a way to convert the argument Component*
to something that some constructor of ImplementB
accepts.
C++ has something called user-defined conversions. You can define conversion operators and converting constructors that define new implicit type conversions between types. Here's the thing: any constructor with a single parameter is a converting constructor, unless it is marked with explicit
. (This is probably a design mistake in C++. But we're stuck with it.)
Therefore, ImplementA(Component*)
defines an implicit conversion from Component*
to ImplementA
. And there's the ImplementB(const ImplementA&)
constructor that would accept a ImplementA
temporary just fine. So the compiler uses this constructor, uses the converting constructor to create the temporary, and the end result is the execution you're seeing.
The solution is to make all these constructors explicit
, and also to define fewer, less confusing constructors. And to use smart pointers to get rid of the memory leaks.
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.
The call to foo
returns a Component*
. When we check the constructors for ImplementB
we find
ImplementB(Component& input);
ImplementB(const ImplementA& impl);
ImplementB(const ImplementB& impl);
So none of these accepts a Component*
.
But "luckily" one of the options is an ImplementA
which can be constructed from the pointer.
And one "user-defined conversion" is allowed when passing a parameter.
foo
returns a Component*
.
ImplementB
doesn't have a constructor that accepts a Component*
. However it has a constructor that accepts a const ImplementA&
.
Now Component*
is implicitly convertible to ImplementA
via the constructor of the latter that accepts a Component*
. So it gets converted, and the resulting ImplementA
temporary is passed by const reference to the appropriate constructor of ImplementB
.
If you value your sanity, you probably don't want any implicit conversions anywhere near your code. To stop implicit conversions of user-defined types, declare all single-argument constructors explicit
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.