Good evening, there are a couple of questions on polymorphism.

1 question:

#include <iostream> #include <string> using namespace std; class Human{ protected: string name; int age; char sex; public: /* v Ваш код v */ Human(string name, int age, char sex) { this-> name = name; this-> age = age; this-> sex = sex; cout << "контструктор Human" << endl; } virtual void Show() { cout << name << endl << age << endl << sex << endl; } virtual ~Human() { cout << "виртуальный деструктор Human" << endl; } }; class Coder: public Human{ protected: float IQ; public: /* v Ваш код v */ Coder(string name, int age, char sex, float IQ):Human(name, age, sex) { this-> IQ = IQ; cout << "конструктор Coder" << endl; } void Show() { cout << IQ << endl; } ~Coder() { cout << "виртуальный деструктор Coder" << endl; } }; int main(){ setlocale(LC_ALL, "RUS"); Human *human = new Human("Tom", 21, 'M'); Human *coder = new Coder("Alice", 19, 'F', 150.6f); human->Show(); coder->Show(); delete human; delete coder; return 0; } /* Консоль: конструктор Human конструктор Human конструктор Coder Tom 21 M 150.6 виртуальный деструктор Human виртуальный деструктор Coder виртуальный деструктор Human */ 

As is known, the destruction of an object of the base class entails the destruction of the object of the derived class, so the virtual destructor of the derived object must be performed before the destructor of the base object.

Therefore, in this case, the objects should be deleted in this order:

  delete coder; delete human; 

Or does the removal order not matter, since these are 2 different objects?

those. when creating an object of a successor — the base constructor is first called, then the successor, and when creating a base object, the base constructor is called and the order of deleting objects does not matter as the order of their creation.

And the phrase “the destruction of a base class object entails the destruction of a derived class object” only applies when it comes to polymorphism?

those. in the case of delete coder this phrase makes sense, since the object of the heir is removed through a pointer to the base class, so the virtual destructor is used

and in the case of delete human , the base class object is deleted from the dynamic memory; therefore, it uses not a virtual destructor, but a normal destructor, which in this case is defined in the class body as a virtual

Confusion arose due to the fact that if you create these objects in automatic memory, then the destructors are called in a logical order (according to the principle, the last one came - the first left):

  Human h("Tom", 21, 'M'); Human *human = &h; Coder c("Alice", 19, 'F', 150.6f); Human *coder = &c; human->Show(); coder->Show(); /* Консоль: конструктор Human конструктор Human конструктор Coder Tom 21 M 150.6 виртуальный деструктор Coder виртуальный деструктор Human виртуальный деструктор Human */ 

2 question:

To implement polymorphism, you can:

create a heir object in dynamic memory:

 Human *p = new Coder; 

create a successor object in automatic memory:

 Coder obj; Human *p = &obj; 

Here I have a contradiction, polymorphism is achieved only with the help of late binding, which means that the object must be created in dynamic memory using the new operator, because it is during the execution of the program that the compiler analyzes the type of object pointed to by the pointer in order to determine which implementation of the virtual method should be called, during the launch of the program this is still unknown.

In this connection, the question is why the creation of an object in automatic memory is considered correct for the implementation of polymorphism?

  • Some kind of porridge. Nothing is clear what you want to ask. - Vlad from Moscow
  • “As you know, the destruction of a base class object entails the destruction of a derived class object” - what, sorry? - VladD
  • I apologize, thoughtlessly wrote. I meant that the virtual destructor of the derived object must be called before the destructor of the base object in order for the derived object to be correctly deleted via a pointer to its base class. - Brainsick

2 answers 2

  • You gave the answer to your first question yourself: these are two completely independent objects and they only have an “inside” order for each destructor that is separate for each object. Therefore, it does not matter in what order you will delete these objects - they have no effect on each other.

  • Your second question is based on the unclear / incorrect premise "polymorphism is achieved only with the help of late binding, which means that the object must be created in the dynamic memory" . Where did you get this from?

    "Late binding" in C ++ means, by definition, only that when you call a virtual method, the specific implementation of this method will be selected according to the dynamic type of the object used in the call. (Despite the presence of the word "dynamic" in this definition, dynamic memory has nothing to do with it at all.) In your case

     Coder obj; Human *p = &obj; 

    that means in the call

     p->Show(); 

    at runtime, the dynamic type of the object *p will be determined, it is determined that this is a Coder , and, accordingly, the Coder::Show() method will be called. That's all. No dynamic memory is needed here.

    (Of course, practical implementations of this mechanism may work in an arbitrary manner, providing the correct functionality. In the traditional implementation, you will not see any explicit analysis of the dynamic type of the object, but you will simply see an indirect call through the so-called virtual methods table , but this is the tenth thing. )

    In fact, you yourself correctly answered this question: "at runtime, the compiler analyzes the type of the object pointed to by the pointer to determine which implementation of the virtual method should be called . " But it’s not at all clear to me why you conclude from this that some part of the dynamic memory is needed here.

  • As I understand it, the dynamic type of an object allows you to determine at what time the program is running on which type of object should you call a virtual method? - Brainsick
  • one
    @Brainsick: Well, yes, that's right. With the only difference that in a typical implementation, when accessing the VMT object *p program immediately goes directly to the correct VMT of the inheriting class and immediately takes the right pointer to the target method from there. (It may well be that this is what you said above.) That is, it is not necessary to explicitly define the dynamic type. But from an abstract conceptual point of view, this is how it works. - AnT
  • one
    @Brainsick: Virtual Method Table - Virtual Methods Table. What you see the difficulty of determining the dynamic type is not clear to me. The dynamic type of the expression is the actual type of the object to which this expression refers. In this example, although the p pointer is declared with the Human * type, the dynamic type of the expression *p is Coder . And how to define it is the compiler's concern. (In practice, it is usually determined through the same VMT. We can say that by what exactly the VMT pointer of the object points to, we can already call the dynamic type of the object.) - AnT
  • one
    @Brainsick: Usually, a virtual destructor call is implemented by the same mechanism as all other methods, i.e. Yes - this is the usual method in the virtual method table. - AnT
  • one
    @Brainsick: Yes, like all other virtual methods. The functions of the destructor are extended, but the virtual call mechanism of it is the same as with the usual virtual method. - AnT

In these sentences, you explicitly delete the objects pointed to by pointers.

 delete human; delete coder; 

In what order you write down these sentences, in that order will remove objects. If, for example, you write these sentences as

 delete coder; delete human; 

then the object pointed to by coder will be deleted first, and then the object pointed to by human will be deleted. These objects are not related to each other, so the removal of one object does not affect the lifetime of another object and its removal.

And the phrase “the destruction of a base class object entails the destruction of a derived class object” only applies when it comes to polymorphism?

This phrase has no meaning.

In this connection, the question is why the creation of an object in automatic memory is considered correct for the implementation of polymorphism?

This question is also meaningless. Polymorphism is not related to the memory in which objects are created.

In this code snippet

 Human h("Tom", 21, 'M'); Human *human = &h; Coder c("Alice", 19, 'F', 150.6f); Human *coder = &c; human->Show(); coder->Show(); 

a pointer named coder type Human * points to an object of a derived class of type Coder , and since the class has a virtual function that is called using a pointer to the base class, polymorphism takes place. It has nothing to do with creating and deleting objects themselves.

The order of object deletion is described by the following quote from the C ++ standard (12.4 Destructors)

8 X-ray X-ray X-ray X-ray telescope (12.6.2), its destructor calls for virtual base classes. All the destructors are referred to as if they were not allowed to receive their virtual code. Bases and members are destroyed of their constructor (see 12.6.2). A return statement (6.6.3) in a destructor might not directly return to the caller; the transfer of the control and the caller Reverse order of their construction

As for creating and deleting objects with automatic memory duration, then (6.6 Jump statements)

2 On the exit from the scope (3.7.3), it’s not possible to do so.

Therefore, in this fragment the skin

 Human h("Tom", 21, 'M'); Human *human = &h; Coder c("Alice", 19, 'F', 150.6f); Human *coder = &c; human->Show(); coder->Show(); 

first, an object h will be created, then an object c will be created, Deletion of these objects will be performed in the reverse order, that is, object c will be deleted first, and object h will be deleted after it.

  • Understood, dynamic memory allocation and dynamic type of an object are two different things. The questions are not quite on the topic, but still: 1) When is it preferable to create an object in an automatic memory, and in which cases - in a dynamic one? Those. in static if placement speed is important, and in dynamic if the object is large? 2) When answering my other question, you gave the definition of a table of pointers to virtual methods, came across the concept of "table of pointers to objects" ( ru.wikipedia.org/wiki/Dynamic_identification_data_name ) do not accidentally know what is meant by this? - Brainsick
  • one
    @Brainsick Usually objects are created in dynamic memory, when complete information about them becomes known only during program execution. Objects are also created in dynamic memory when it is necessary that the life of an object does not depend on the domain where the object is created. As for the second question, this is a technical implementation of identifying objects using pointers to objects. - Vlad from Moscow