почему два разных способа инициализации объектов дают разные результаты - PullRequest
0 голосов
/ 25 сентября 2018

Рассмотрим следующий код

#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 голосов
/ 25 сентября 2018

Статические переменные-члены типа класса представляют хранилище с жизненным циклом всего процесса.Он инициализируется как таковой, в некоторый момент до того, как точка входа в программу - начало 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 
0 голосов
/ 25 сентября 2018

Легко понять, что всякий раз, когда создается экземпляр экземпляра (объекта), вызывается связанный конструктор

Теперь мой вопрос таков: почему в первом случае конструктор A вызывается только один раз, а во втором коде он вызывается дважды.

Вы создаете второйобъект непосредственно в стеке, и конструктор вызывается в последнем случае, первый - статический, а второй - путем создания объекта в стеке с помощью инструкции ниже.

A a ;

В первом случае, вместо конструктора, конструктор копированияпоэтому вы не получаете заявление на печать во второй раз.

A a = b1.getA(); 
0 голосов
/ 25 сентября 2018

В вашем первом коде

A a = b1.getA(); 

вызывается конструктор копирования A, который не генерирует никакого вывода.Определите это сами, и вы получите вывод, аналогичный вашему второму коду.

0 голосов
/ 25 сентября 2018

Теперь мой вопрос таков: почему в первом случае конструктор A вызывается только один раз, тогда как во втором коде он вызывается дважды.

Потому что в первом случае вы инициализируете по умолчанию только статический B::a, а инициализируете копией локальный a.

Во втором вы инициализируете по умолчанию оба объекта.

Принципиальное отличие состоит в том, что вы печатаете только сообщение в конструкторе по умолчанию и ничего не печатаете в конструкторе копирования.

Также два вывода: & a и & B:: a разные, значит, это два разных объекта.

Это правильно.a является локальной переменной, а B::a является статической переменной-членом.Это разные объекты.

0 голосов
/ 25 сентября 2018

Хмм, B::a - это статический экземпляр B-члена (в общем случае) совершенно обычного класса A.Итак, первый зарегистрированный конструктор A - это B::a, который должен быть инициализирован до того, как элемент управления войдет в main, но затем вы создаете отдельный экземпляр A локально для main, он создается впорядок наряду с другими локальными переменными main (здесь, сразу после всех B с), и он, естественно, отличается от B::a.

...