问题
We can call a constructor using qualified-name, although the constructor doesn't have a name. Indeed 3.4.3.2/2:
In a lookup in which function names are not ignored and the nested-name-specifier nominates a class C:
— if the name specified after the nested-name-specifier, when looked up in C, is the injected-class-name of C (Clause 9), or
[...]
the name is instead considered to name the constructor of class C.
Consider the following example:
#include <iostream>
using std::cout;
using std::endl;
struct A
{
virtual void foo()
{
cout << "A" << endl;
}
A(){ }
};
struct B : A
{
virtual void foo()
{
cout << "B" << endl;
}
B()
{
foo();
}
};
struct C : B
{
virtual void foo()
{
cout << "C" << endl;
}
C() : B(){ }
};
C c;
int main()
{
c.foo();
C::C(); // Prints B
}
demo
The line C::C() prints B. But it's unclear. Section 12.7/4 says:
When a virtual function is called directly or indirectly from a constructor or from a destructor, including during the construction or destruction of the class’s non-static data members, and the object to which the call applies is the object (call it x) under construction or destruction, the function called is the final overrider in the constructor’s or destructor’s class and not one overriding it in a more-derived class
In an explicit constructor call c has already fully-contructed. So the rule I cited cannot be used to explain such behavior. Is it UB at all? Could you explain it?
回答1:
We can call a constructor using qualified-name, although the constructor doesn't have a name.
Your premise is completely wrong. In the very same paragraph you cited (§3.4.3.1 [class.qual]/p2):
Such a constructor name shall be used only in the declarator-id of a declaration that names a constructor or in a using-declaration.
Is C::C(); a declaration that names a constructor? No. Is it a using-declaration? Obviously not.
It's ill-formed. Clang seems to consider it to name the type instead, for some reason - probably a bug (its handling of injected-class-names is also buggy in other respects).
I also have no idea how you came to the conclusion that the behavior of C::C(); - which, incidentally, only makes any sense if you consider C::C to name the type - could possibly be affected by the state of c, which appears nowhere in the expression nor in any of the relevant functions.
A hypothetical explicit constructor call on an object would have to look like c.C::C();, because the constructor is a non-static member function. And it makes no sense whatsoever to permit you to call a constructor on an already-constructed object - what does that even mean?
回答2:
The line...
C::C();
is outputting...
B
because foo() is being called from within B's constructor so it'll use B's version of foo().
Any time C's constructor is called,
C::C() calls A's constructor which calls B's constructor in which foo() is called so B's version of foo() is used, and then C's constructor body (which you left empty) is finally called.
Let's ignore the fact that calling C::C() from main() like that doesn't conform to C++ standards. You seem to be misinterpreting part of Section 12.7/4:
...the function called is the final overrider in the constructor’s or destructor’s class and not one overriding it in a more-derived class
The call to foo is in B so the
...constructor's class...
is B and therefore
...not one overriding it in a more-derived class.
(which would be C).
You also mention "In an explicit constructor call C has already fully-contructed." The line...
C c;
will not change the behavior mentioned in Section 12.7/4. foo() is still called B's constructor and therefore
...the function called is the final overrider in the construtor's or destructor's class.
来源:https://stackoverflow.com/questions/25541010/explicitly-constructor-and-virtual-function-call-during-the-object-lifetime