【问题标题】:Explicitly constructor and virtual function call during the object lifetime在对象生命周期内显式调用构造函数和虚函数
【发布时间】:2014-08-28 04:58:26
【问题描述】:

我们可以使用限定名称调用构造函数,尽管构造函数没有名称。确实是 3.4.3.2/2:

在不忽略函数名的查找中, 嵌套名称说明符指定了一个 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
}

demo

C::C() 行打印 B。但不清楚。第 12.7/4 节说:

当一个虚函数被直接或间接调用时 构造函数或析构函数,包括在构造过程中或 销毁类的非静态数据成员,以及 object to 调用应用的对象是对象(称为 x)正在建设中或 destruction,调用的函数是 构造函数或析构函数的类,而不是一个覆盖它的类 更多派生类

在显式构造函数中调用c 已经完全构造好了。所以我引用的规则不能用来解释这种行为。是UB吗?你能解释一下吗?

【问题讨论】:

  • C::C();与对象c有什么关系?

标签: c++ constructor


【解决方案1】:

我们可以使用限定名称调用构造函数,尽管构造函数没有名称。

你的前提是完全错误的。在您引用的非常相同段落中(§3.4.3.1 [class.qual]/p2):

这样的构造函数名称只能在declarator-id中使用 命名构造函数或在 using-declaration 中的声明。

C::C(); 是一个命名构造函数的声明吗?不。它是 using-declaration 吗?显然不是。

格式不正确。出于某种原因,Clang 似乎认为它改为命名类型 - 可能是一个错误(它对 injected-class-names 的处理在其他方面也是错误的)。


我也不知道你是如何得出这样的结论的:C::C(); 的行为——顺便说一句,只有当你考虑用C::C 来命名类型时才有意义——可能会受到@ 状态的影响987654324@,它既没有出现在表达式中,也没有出现在任何相关函数中。

对对象的假设显式构造函数调用必须看起来像c.C::C();,因为构造函数是一个非静态成员函数。允许您在已经构造的对象上调用构造函数是没有任何意义的——这甚至意味着什么?

【讨论】:

  • 我的第一个想法是 C::C 应该命名一个类型,因为 Cinjected-class-name,但是正如您所说的那样,正是引用的文本表示它被认为是在此上下文中命名构造函数
  • 这是我的疏忽。 C::C() 显然没有任何意义。但是 clang 没有抛出编译时错误,我认为它是正确的。我明白没有办法显式地调用构造函数。谢谢。
  • @MattMcNabb 但作为 T.C.注意构造函数是非静态成员函数。因为,程序一定是格式错误的。
【解决方案2】:

线...

C::C();

正在输出...

B

因为foo() 是从B 的构造函数中调用的,所以它将使用Bfoo() 版本。

任何时候C的构造函数被调用, C::C() 调用A 的构造函数,该构造函数调用B 的构造函数,其中调用了foo(),因此使用Bfoo() 版本,然后使用C 的构造函数主体(其中你留空)最终被调用。


让我们忽略这样一个事实,即从 main() 调用 C::C() 不符合 C++ 标准。您似乎误解了第 12.7/4 节的部分内容:

...调用的函数是构造函数或 析构函数的类,而不是在派生更多的类中覆盖它

对 foo 的调用是在B 所以

...构造函数的类...

B,因此

...没有人在派生更多的类中覆盖它。

(应该是C)。

您还提到“在显式构造函数中调用C 已经完全构造。”线...

C c; 

不会改变第 12.7/4 节中提到的行为。 foo() 仍然被称为 B 的构造函数,因此

...调用的函数是构造函数或析构函数类中的最终覆盖器。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-02-15
    • 1970-01-01
    • 1970-01-01
    • 2012-01-28
    • 2017-04-30
    • 2023-04-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多