我们可以使用qualified-name调用构造函数,尽管构造函数没有名称。确实是3.4.3.2/2:
在查找中,不忽略函数名称和 nested-name-specifier指定一个C类:
- 如果在C中查找时,在嵌套名称说明符之后指定的名称是 C的注入类名(第9条)或
[...]
该名称被认为是为C类的构造函数命名。
考虑以下示例:
#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
}
第C::C()
行打印B.但目前还不清楚。第12.7 / 4节说:
直接或间接从a调用虚函数时 构造函数或析构函数,包括在构造期间或 破坏类的非静态数据成员,对象 到 调用适用是正在构建的对象(称之为x)或 销毁,被调用的函数是最终的覆盖者 构造函数或析构函数的类,而不是覆盖它的一个 更多派生的课程
在显式构造函数中,调用c
已经完全构造。所以我引用的规则不能用来解释这种行为。它是UB吗?你能解释一下吗?
答案 0 :(得分:1)
我们可以使用qualified-name调用构造函数,尽管构造函数没有名称。
你的前提是完全错误的。在您引用的非常相同的段落中(§3.4.3.1[class.qual] / p2):
这样的构造函数名称只能在a的 declarator-id 中使用 命名构造函数或 using-declaration 的声明。
C::C();
是一个命名构造函数的声明吗?不是。它是使用声明吗?显然不是。
这是不正确的。由于某种原因,Clang似乎考虑将其命名为类型 - 可能是一个错误(它对注入类名的处理在其他方面也有错误。)
我也不知道你是怎么得出这样的结论:C::C();
的行为 - 顺便提一下,如果你考虑C::C
来命名这个类型,那么它可能会受到影响c
的状态,在表达式和任何相关函数中都没有出现。
对对象的假设显式构造函数调用必须看起来像c.C::C();
,因为构造函数是非静态成员函数。允许你在已经构造的对象上调用构造函数是没有任何意义的 - 这甚至意味着什么?
答案 1 :(得分:0)
线......
C::C();
正在输出......
B
因为foo()
是从B
的构造函数中调用的,因此它将使用B
的{{1}}版本。
任何时候调用foo()
的构造函数,
C
调用C::C()
的构造函数,该构造函数调用A
的构造函数,其中B
被调用,因此使用了foo()
的{{1}}版本,然后B
的构造函数体(你留空)终于被调用了。
让我们忽略从foo()
调用C
这样的事实不符合C ++标准的事实。您似乎误解了第12.7 / 4节的一部分:
...被调用的函数是构造函数中的最终覆盖 析构函数的类,而不是在更派生的类中重写它
对foo的调用在C::C()
中,所以
...构造函数的类......
是main()
,因此
...不是一个在更派生的类中重写它。
(这将是B
)。
你还提到“在一个明确的构造函数中,B
已经完全构建了。”这条线...
C
不会改变第12.7 / 4节中提到的行为。 C
仍称为C c;
的构造函数,因此
...被调用的函数是construtor或析构函数类中的最终覆盖。