【问题标题】:why do the two different ways of initialising objects give different outputs为什么初始化对象的两种不同方式会给出不同的输出
【发布时间】:2018-09-25 07:33:59
【问题描述】:

考虑下面的代码

#include <iostream> 
    using namespace std; 

    class A 
    { 
        int x; 
    public: 
        A() { cout << "A's constructor called " << endl; } 
    }; 

    class B 
    { 
        public:
        static A a; 

        B() { cout << "B's constructor called " << endl; } 
        static A getA() { return a; } 
    }; 

    A B::a; // definition of a 

    int main() 
    { 
        B b1, b2, b3; 
        A a = b1.getA(); 

        cout<<&a<<endl;  

        cout<<&B::a;

        return 0; 
    } 

输出是

A's constructor called 
B's constructor called 
B's constructor called 
B's constructor called 
0x7fff03081280
0x601194

现在让我们考虑另一个类似的代码

    #include <iostream> 
    using namespace std; 

    class A 
    { 
        int x; 
    public: 
        A() { cout << "A's constructor called " << endl; } 
    }; 

    class B 
    { 
        public:
        static A a; 

        B() { cout << "B's constructor called " << endl; } 
        static A getA() { return a; } 
    }; 

    A B::a; // definition of a 

    int main() 
    { 
        B b1, b2, b3; 
        A a ;
        a= b1.getA(); 

        cout<<&a<<endl;  
        cout<<&B::a;  

        return 0; 
    } 

输出是

A's constructor called 
B's constructor called 
B's constructor called 
B's constructor called 
A's constructor called 
0x7ffc485a1070
0x601194

现在我的问题是为什么在第一种情况下 A 的构造函数只被调用一次,而在第二种代码中它被调用两次。

另外两个输出 &a 和 &B::a 是不同的,所以这意味着它们是两个不同的对象。

请解释为什么会这样。

【问题讨论】:

    标签: c++ constructor static-members


    【解决方案1】:

    在您的第一个代码中

    A a = b1.getA(); 
    

    A 的复制构造函数被调用,它不会产生任何输出。自己定义它,你会得到与第二个代码类似的输出。

    【讨论】:

      【解决方案2】:

      嗯,B::a 是 B 的(公共)静态成员实例,它是一个非常普通的类 A。所以,记录的第一个A 的构造函数是B::a 的构造函数,它应该在控制进入main 之前被初始化,但是接下来你创建一个单独的A 实例,它位于main 的本地,它是在与其他main 的局部变量一起排序(这里,在所有Bs 之后),它自然不同于B::a

      【讨论】:

        【解决方案3】:

        现在我的问题是为什么在第一种情况下 A 的构造函数只被调用一次,而在第二种代码中它被调用两次。

        因为在第一种情况下,您仅默认初始化静态 B::a,并复制初始化本地 a

        在第二个你默认初始化两个对象。

        关键的区别在于您只在默认构造函数中打印一条消息,而不在复制构造函数中打印任何内容。

        另外两个输出 &a 和 &B::a 是不同的,所以这意味着它们是两个不同的对象。

        没错。 a 是一个局部变量,而B::a 是一个静态成员变量。它们是不同的对象。

        【讨论】:

          【解决方案4】:

          类类型的静态成员变量表示具有进程范围生命周期的存储。它在到达程序入口点之前的某个时间点被初始化 - main() 的开头 - 到达。这是第一个构造函数调用。

          线

          A a = b1.getA();
          

          通过调用复制构造函数初始化对象a,通过返回值优化和复制省略,没有默认构造函数调用。

          第二种变体:

          A a;            // A() call
          a = b1.getA();  // operator= call
          

          修改类

          class A 
          { 
              int x; 
          public: 
              A(const A& a): x(a.x) { cout << "A's copy constructor called " << endl; } 
              A(A&& a): x(a.x) { a.x = 0; cout << "A's move constructor called " << endl; }
              const A& operator=(const A& a) { x = a.x; cout << "A's copy operator= called " << endl; } 
              A() { cout << "A's constructor called " << endl; } 
          }; 
          

          在第一种情况下会给出这个输出:

          A's constructor called 
          B's constructor called 
          B's constructor called 
          B's constructor called 
          A's copy constructor called 
          

          第二种情况会导致:

          A's constructor called 
          B's constructor called 
          B's constructor called 
          B's constructor called 
          A's constructor called 
          A's copy constructor called 
          A's copy operator= called 
          

          【讨论】:

            【解决方案5】:

            很容易理解,每当类实例(对象)被创建时,关联的构造函数就会被调用。

            现在我的问题是为什么在第一种情况下 A 的构造函数只被调用一次,而在第二种代码中它被调用两次。

            您直接在堆栈中创建第二个对象,并且在以后的情况下调用构造函数,第一个是静态的,第二个是通过以下语句在堆栈中创建对象。

            A a ;
            

            在第一种情况下,复制构造函数被调用,而不是构造函数,这就是为什么你第二次没有得到 print 语句的原因。

            A a = b1.getA(); 
            

            【讨论】:

            • 两种情况下都有两个独立的对象。
            • 这对之前的答案有什么补充?
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2022-12-05
            • 1970-01-01
            • 1970-01-01
            • 2015-11-27
            相关资源
            最近更新 更多