为什么两种不同的初始化对象的方式给出不同的输出

时间:2018-09-25 07:34:00

标签: c++ constructor static-members

考虑以下代码

#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也不同,所以这意味着它们是两个不同的对象。

请解释为什么会这样。

5 个答案:

答案 0 :(得分:3)

在您的第一个代码中

A a = b1.getA(); 

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

答案 1 :(得分:1)

嗯,B::a是B的(公共)静态成员实例,否则是非常普通的类A。因此,记录的第一个A的构造函数是B::a的构造函数,应该在控件进入main之前对其进行初始化,但是接下来您要在本地创建一个A的单独实例main,它是与其他main的局部变量(在这里,紧随所有B之后)一起按顺序构造的,自然与B::a不同。 / p>

答案 2 :(得分:1)

  

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

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

在第二个中,您默认初始化了两个对象。

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

  

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

是正确的。 a是局部变量,而B::a是静态成员变量。它们是不同的对象。

答案 3 :(得分:1)

类类型的静态成员变量表示具有整个过程寿命的存储。就这样初始化它,到达程序入口点之前的某个点-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 

答案 4 :(得分:0)

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

  

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

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

path = 'C:\\Users\\ABC\\Desktop\\'
files = glob.glob(path+'*.csv')

在第一种情况下,不是调用构造函数,而是调用拷贝构造函数,因此这就是为什么您第二次不获取print语句的原因。

A a ;