【问题标题】:Does calling a C++ constructor from another member function/constructor execute the initializer list?从另一个成员函数/构造函数调用 C++ 构造函数是否会执行初始化列表?
【发布时间】:2012-05-14 08:11:32
【问题描述】:

在 C++ 对象中,当您从另一个构造函数或成员函数调用构造函数时(在对象已经构造之后),您正在调用的构造函数的初始化列表是否仍会执行?

【问题讨论】:

    标签: c++ list constructor initializer


    【解决方案1】:

    在 C++11 中,您可以让构造函数将工作委托给同一类中的另一个构造函数,例如1

    #include <iostream>
    struct SomeType  {
        int number;
    
        SomeType(int new_number) : number(new_number) {}
        SomeType() : SomeType(42) {}
    };
    
    int main() {
      SomeType a;
      std::cout << a.number << std::endl;
    }
    

    在这种情况下,禁止在此委托之后有一个初始化列表,例如将前面的示例更改为:

    SomeType() : SomeType(42), number(0) {}
    

    是一个错误。


    如果问题是“给定继承关系,初始化列表是否仍会被调用?”答案是肯定的,例如

    #include <iostream>
    struct SomeBase {
      SomeBase(int) {}
    };
    
    struct SomeType : SomeBase {
        int number;
    
        SomeType(int new_number=0) : SomeBase(new_number), number(new_number) {}
    };
    
    int main() {
      SomeType a;
      std::cout << a.number << std::endl;
    }
    

    这很好,完全按照您的希望工作。


    在另一个构造函数中直接调用构造函数是不合法的,在 C++11 之前的 C++ 中也不允许构造函数委托,所以类似于:

    #include <iostream>
    
    struct SomeType {
        int number;
    
        SomeType(int new_number) : number(new_number) {}
        SomeType() {
          SomeType::SomeType(0); // Error!
        }
    };
    
    int main() {
      SomeType a;
      std::cout << a.number << std::endl;
    }
    

    是一个错误,不能直接表达。

    以下示例(我猜这是您在写问题时的想法)示例不是错误,但并没有达到您希望的效果:

    #include <iostream>
    
    struct SomeType {
        int number;
    
        SomeType(int new_number) : number(new_number) {}
        SomeType() {
          SomeType(0); 
          number = 42;
        }
    };
    
    int main() {
      SomeType a;
      std::cout << a.number << std::endl;
    }
    

    这里没有参数的构造函数构造了一个匿名的 SomeType 临时实例。它与最初调用构造函数的实例完全不同。这是完全合法的,但可能不是您的本意。如果你这样做,如果你不小心,你可能会产生无限递归的风险,我认为如果你最终做了这样的事情,这可能是设计问题的一个很好的指标!

    1源自维基百科C++11 article

    【讨论】:

      【解决方案2】:

      我假设您指的是从派生类的初始化列表中调用基类构造函数。假设是这种情况,那么首先执行 BASE 类的构造函数(包括其初始化列表),然后调用派生类的初始化列表。

      如果您想知道 - 基类构造函数总是在为派生类执行初始化程序列表之前调用,即使对基类构造函数的调用显式出现在派生类初始化程序的中间或末尾列表(以及它是否出现在开头)。原因是初始化列表中的项目是按照它们出现在类头文件中的类 DECLARATION 中的顺序执行的,而不是按照它们出现在构造函数定义的初始化列表中的顺序。而且,base 类构造函数永远不会在 derived 类声明中声明。 C++ 要求基类构造函数始终在派生类构造函数之前调用——无论对基类构造函数的调用是否显式出现在派生类的初始化列表中——也不管它出现在初始化列表中的什么位置。

      【讨论】:

        【解决方案3】:

        不要从另一个方法或另一个构造函数显式调用构造函数。

        如果确实需要,请使用两阶段初始化,在构造对象后调用Init() 类型的方法。

        【讨论】:

          【解决方案4】:

          您不能显式调用构造函数,只能通过 new 或堆栈上的对象构造来调用。有一些方法可以破解它(例如放置新),但不要这样做,只需使用两阶段构造和初始化。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-06-23
            • 1970-01-01
            • 2011-03-24
            • 1970-01-01
            相关资源
            最近更新 更多