Как может быть, что деструктор называется, но не конструктор до этого? - PullRequest
0 голосов
/ 01 мая 2020

В настоящее время я изучаю объектно-ориентированную особенность c ++. Я написал фрагмент кода, чтобы проверить, как работает наследование и полиморфизм. Вот часть кода:

    class Person
{
    public:
    Person()
    {
        cout << "Person constructed\n";
    }

    virtual void introduce()
    {
        cout << "hi from person" << endl;
    }

    ~Person()
    {
        cout << "Person destructed\n";
    }
};

class Student : public Person 
{
    public:
    Student()
    {
        cout << "Student constructed\n";
    }

    void introduce()
    {
        cout << "hi from student" << endl;
    }

    ~Student()
    {
        cout << "Student destructed\n";
    }
};

class Farmer : public Person 
{
    public:
    Farmer()
    {
        cout << "Farmer constructed\n";
    }

    void introduce()
    {
        cout << "hi from farmer" << endl;
    }

    ~Farmer()
    {
        cout << "Farmer destructed\n";
    }
};

class SJW : public Student
{
    public:
    SJW()
    {
        cout << "SJW constructed\n";
    }

    ~SJW()
    {
        cout << "SJW destructed\n";
    }
};

void whoisthis3(Person object)
{
    object.introduce();
}

int main()
{
    Student mark;
    SJW bigred;
    Farmer max;

    cout << endl;

    whoisthis3(mark);
    whoisthis3(max);
    whoisthis3(bigred);

    cout << endl;

    return 0;
}

Это вывод, который он производит:

Person constructed
Student constructed
Person constructed
Student constructed
SJW constructed
Person constructed
Farmer constructed

hi from person
Person destructed
hi from person
Person destructed
hi from person
Person destructed

Farmer destructed
Person destructed
SJW destructed
Student destructed
Person destructed
Student destructed
Person destructed

Эти производные классы создаются и разрушаются в начале и в конце, как и ожидалось , Но как может быть так, что при выполнении метода whoisthis3 вызывается деструктор Person? Что там происходит?

Ответы [ 2 ]

2 голосов
/ 01 мая 2020

Рассмотрим следующую простую программу:

struct A 
{
    A() { std::cout << "construct A\n";  }
    ~A() { std::cout << "destruct A\n";  }  
};

int main()
{
  A a;
}

Это печатает:

constructs A
destructs A

, как и ожидалось.

Теперь давайте добавим простую функцию:

void f(A a) {}

и назовите его:

int main()
{
  A a;
  f(a);
}

и мы увидим:

construct A
destruct A
destruct A

Теперь, откуда взялся этот дополнительный destruct A? а где соответствующий construct A? Ответ: при вызове f вызывается конструктор копирования по умолчанию. Если вы напечатаете материал в конструкторе копирования, например:

A(A const&) { std::cout << "copy-construct A\n"; }

, вы получите вывод:

construct A
copy-construct A
destruct A
destruct A

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

С другой стороны, если f принимает аргумент по ссылке, например так:

void f(A& a) {}

, то конструктор копирования не вызывается (поскольку копия не создается ), и результат будет:

construct A
destruct A
1 голос
/ 01 мая 2020
void whoisthis3(Person object)
{
    object.introduce();
}

Эта функция принимает свой параметр object по значению. Это означает, что новый объект Person создается как копия объекта, который вы передаете whoisthis3. Поскольку вы явно не определили конструктор копирования Person, он использует конструктор копирования по умолчанию, сгенерированный компилятором. Когда функция заканчивается, ее параметр object уничтожается, и вы видите оператор, напечатанный ее деструктором.


Обратите внимание, что, как вы заметили, whoisthis3 всегда будет вызывать Person::introduce, так как object - это Person, а не любой тип, производный от него. Это обычно называется нарезка объекта .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...