简体   繁体   English

如何在C ++中实现构造函数和析构函数?

[英]How are constructors and destructors implemented in C++?

I have 2 classes Base and Derived (derived publically from Base). 我有2个基本类和派生类(从Base公开派生)。 When I write - 当我写-

Derived * d1 = new Derived;
delete d1;

Compiler sees that d1 is a Derived type object. 编译器看到d1是派生类型对象。 So it calls the derived class constructor (which calls the base class constructor). 因此,它将调用派生类构造函数(后者将调用基类构造函数)。 I have 2 questions here - 我在这里有2个问题-

1) Why do we follow this order? 1)为什么我们要遵循这个顺序?

2) How do these constructors work together to allocate memory? 2)这些构造函数如何一起工作以分配内存? I need some implementation details 我需要一些实施细节

Now the next statement is delete d1. 现在,下一个语句是delete d1。 So compiler sees that d1 is a derived type object and so calls the destuctor of derived class (which calls the destructor of base class after deleting the derived class members). 因此,编译器认为d1是派生类型对象,因此调用了派生类的析构函数(删除了派生类成员后调用了基类的析构函数)。 I have one question here - 我在这里有一个问题-

1) How do these destructors work together? 1)这些析构函数如何协同工作? Lets say the derived class destructor is passed the address of d1 in memory. 可以说派生类的析构函数在内存中传递了d1的地址。 How do these destructors free up the space now? 这些析构函数如何释放空间?

That code will not compile. 该代码将无法编译。 You cannot delete an automatic instance, you must use new to allocate the instance in order to use delete on it. 您不能delete自动实例,必须使用new来分配实例,以便在其上使用delete

When it comes to constructor order, I guess it just makes sense to run them so that more specialized classes can depend on the more general parts having already been done. 说到构造函数顺序,我认为运行它们很有意义,这样,更专业的类可以依赖于已经完成的更通用的部分。

The memory layout of each class is known by the compiler, from inspecting the complete class declaration and recursing up through any and all superclasses. 编译器通过检查完整的类声明并通过任何超类和所有超类递归,可以知道每个类的内存布局。

1) By default, the base class constructor is called automatically. 1)默认情况下,基类构造函数会自动调用。 However, the derived constructor is allowed to call the base class constructor explicitly in its initializer list. 但是,允许派生的构造函数在其初始化程序列表中显式调用基类构造函数。 This would not be possible if the constructors were not executed derived-class-first. 如果没有执行构造函数派生类优先,那将是不可能的。

Derived::Derived() : foo( 42 ), bar( 7 ), Base( 1, 2 ) { }

2) The compiler knows the memory footprint of the derived class (as all member variables are known at compile time), and allocates enough memory to hold both the base class and the derived class members. 2)编译器知道派生类的内存占用(因为所有成员变量在编译时都是已知的),并分配足够的内存以容纳基类和派生类成员。 Details on the memory layout are specified by the ABI used by your system. 内存布局的详细信息由系统使用的ABI指定。

3) Destructors do more than just freeing up the memory. 3)析构函数的作用不只是释放内存。 Actually, the destructors do not free up memory required to hold any member variables - only, where necessary, memory that member pointers point to. 实际上,析构函数不会释放保存任何成员变量所需的内存-仅在必要时释放成员指针指向的内存。

The code example you give wouldn't compile. 您提供的代码示例无法编译。 delete works on pointers, not objects. delete适用于指针,而不适用于对象。

I don't think C++ itself (the language standard) says anything about how memory is used to represent instances of types that use inheritance. 我不认为C ++本身(语言标准)关于内存如何用于表示使用继承的类型实例的任何说法。 However, in most implementations a single chunk of memory is allocated from the free store that is large enough to hold all the data of Base and Derived . 但是,在大多数实现中,从免费存储中分配了一块内存,该内存的大小足以容纳BaseDerived所有数据。 When an instance of Derived is deleted, both constructors run and then the single memory block is freed. 删除Derived的实例时,两个构造函数都将运行,然后释放单个内存块。

Similarly, if an instance of Derived is an embedded data member of some class Container , then the memory block that holds an instance of Container will be made large enough to hold Derived (and hence Base ) and all the other data of Container . 类似地,如果Derived的实例是某个类Container的嵌入式数据成员,那么容纳Container的实例的内存块将变得足够大,可以容纳Derived (因此也就是Base )以及Container所有其他数据。

(1) The base class does not depend on the derived class, but the other way around is possible. (1)基类不依赖于派生类,但是反之亦然。 Ie a Base class cannot know which fields any Derived class has, so Base::Base won't and can't touch them. 也就是说, Base类无法知道任何Derived类具有哪些字段,因此Base::Base不会也无法接触它们。 The other way around is possible, Derived::Derived can access Base::member . 另一种可能的方式是, Derived::Derived可以访问Base::member Therefore, Base::member is initialized by Base::Base before Derived::Derived gets the chance to use Base::member`. 因此,在Derived::Derived gets the chance to use之前由Base::Base初始化Base::member Derived::Derived gets the chance to use Base :: member`。

(2) constructors don't allocate memory. (2)构造函数不分配内存。 That's new 's task. 那是new的任务。 Or if the object is a global, the compilers'. 或者,如果对象是全局对象,则为编译器的对象。 The constructor is called with this already pointing to the allocated memory; 调用构造函数时, this已经指向分配的内存; it need just fill in the members at that location. 它只需要填写该位置的成员即可。

In the case of a base and derived constructor, one common implementation inserts the call to the Base constructor in the generated code for the Derived constructor. 在使用基本构造函数和派生构造函数的情况下,一个常见的实现在对派生构造函数的生成代码中插入对基本构造函数的调用。 With single inheritance, the Base and Derived class usually share the same this pointer, so the Derived constrcutor can then pass the same pointer that it got. 通过单继承,Base和Derived类通常共享相同的this指针,因此Derived构造函数可以传递它获得的相同指针。

(1) [sic] Just like constructors don't allocate memory, destructors don't free it. (1) [sic]就像构造函数不分配内存一样,析构函数也不释放内存。 That's the task of delete - and again, for globals the compiler would do it. 那是delete的任务-同样,对于全局变量,编译器会执行delete操作。

When constructing, constructors are called from the highest base class until the oneof the most derived, which will be called the latest. 构造时,从最高的基类调用构造函数,直到最高级的基类中的一个称为最新的构造器。

When destructors are called, it's the reverse order. 调用析构函数时,顺序相反。 First is called the destuctor of the most derived, until the one of the highest base class. 首先被称为派生最多的分解器,直到被称为最高基类的析构器。

While in inheritance, the compiler should know what it is inheriting. 在继承时,编译器应该知道它在继承什么。 It should know what the Base class consists of. 它应该知道Base类的组成。 It cannot inherit from a class, which it doesn't have any idea.. So, it does make sense that the Base class constructor is called first and then the Derived . 它不能从没有任何想法的类继承。因此,先调用Base类构造函数然后再调用Derived确实有意义。

And in the case of Destruction, if the Base destructor is being called first and gets destructed, the Derived class may still be using the Base class members which becomes invalid.. Hence the Destruction is the exact inverse of the construction.. 在Destruction的情况下,如果首先调用Base析构函数并对其进行了Derived ,则Derived类可能仍在使用Base类成员,这将变得无效。因此,Destruction是该构造的确切逆函数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM