constructor and destructor

本文详细解析了构造函数与析构函数的区别,包括完整对象构造函数、基对象构造函数、分配对象构造函数、完整对象析构函数、基对象析构函数和删除对象析构函数,并通过代码示例展示了它们在不同继承情况下的应用。同时,解释了构造函数和析构函数的不同时序和调用方式。

 <ctor-dtor-name> ::= C1   # complete object constructor
                 ::= C2   # base object constructor
                 ::= C3   # complete object allocating constructor
                 ::= D0   # deleting destructor
                 ::= D1   # complete object destructor
                 ::= D2   # base object destructor

 

•The "complete object constructor". It additionally constructs virtual base classes.
•The "base object constructor". It creates the object itself, as well as data members and non-virtual base classes.
•The "allocating object constructor". It does everything the complete object constructor does, plus it calls operator new to actually allocate the memory... but apparently this is not usually seen.
•D2 is the "base object destructor". It destroys the object itself, as well as data members and non-virtual base classes.
•D1 is the "complete object destructor". It additionally destroys virtual base classes.
•D0 is the "deleting object destructor". It does everything the complete object destructor does, plus it calls operator delete to actually free the memory.

 

There are usually two variants of the constructor (not-in-charge / in-charge) and three of the destructor (not-in-charge / in-charge / in-charge deleting).

The not-in-charge ctor and dtor are used when handling an object of a class that inherits from another class using the virtual keyword, when the object is not the complete object (so the current object is "not in charge" of constructing or destructing the virtual base object). This ctor receives a pointer to the virtual base object and stores it.

The in-charge ctor and dtors are for all the other cases, i.e. if there is no virtual inheritance involved; if the class has a virtual destructor, the in-charge deleting dtor pointer goes into the vtable slot, while a scope that knows the dynamic type of the object (i.e. for objects with automatic or static storage duration) will use the in-charge dtor (because this memory should not be freed).

Code example:

struct foo {     foo(int);     virtual ~foo(void);     int bar; };  struct baz : virtual foo {     baz(void);     virtual ~baz(void); };  struct quux : baz {     quux(void);     virtual ~quux(void); };  foo::foo(int i) { bar = i; } foo::~foo(void) { return; }  baz::baz(void) : foo(1) { return; } baz::~baz(void) { return; }  quux::quux(void) : foo(2), baz() { return; } quux::~quux(void) { return; }  baz b1; std::auto_ptr<foo> b2(new baz); quux q1; std::auto_ptr<foo> q2(new quux); Results:

•The dtor entry in each of the vtables for foo, baz and quux point at the respective in-charge deleting dtor.
•b1 and b2 are constructed by baz() in-charge, which calls foo(1) in-charge
•q1 and q2 are constructed by quux() in-charge, which falls foo(2) in-charge and baz() not-in-charge with a pointer to the foo object it constructed earlier
•q2 is destructed by ~auto_ptr() in-charge, which calls the virtual dtor ~quux() in-charge deleting, which calls ~baz() not-in-charge, ~foo() in-charge and operator delete.
•q1 is destructed by ~quux() in-charge, which calls ~baz() not-in-charge and ~foo() in-charge
•b2 is destructed by ~auto_ptr() in-charge, which calls the virtual dtor ~baz() in-charge deleting, which calls ~foo() in-charge and operator delete
•b1 is destructed by ~baz() in-charge, which calls ~foo() in-charge
Anyone deriving from quux would use its not-in-charge ctor and dtor and take on the responsibility of creating the foo object.

In principle, the not-in-charge variant is never needed for a class that has no virtual bases; in that case, the in-charge variant is then sometimes called unified, and/or the symbols for both in-charge and not-in-charge are aliased to a single implementation.

 

 

文章来源: http://stackoverflow.com/questions/6613870/gnu-gcc-g-why-does-it-generate-multiple-dtors/6614369#6614369

// Lab 2: GradeBook.cpp // Member-function definitions for class GradeBook. #include <iostream> using namespace std; // include definition of class GradeBook from GradeBook.h #include "GradeBook.h" // constructor initializes courseName and instructorName // with strings supplied as arguments GradeBook::GradeBook( string course, string instructor ) { setCourseName( course ); // initializes courseName setInstructorName( instructor ); // initialiZes instructorName } // end GradeBook constructor // function to set the course name void GradeBook::setCourseName( string name ) { courseName = name; // store the course name } // end function setCourseName // function to retrieve the course name string GradeBook::getCourseName() { return courseName; } // end function getCourseName /* write code to define a get member function for the instructor's name */ /* write code to define a set member function for the instructor's name */ string GradeBook::getInstructorName() { return instructorName; } // end function getInstructorName // function to set the instructor's name void GradeBook::setInstructorName( string name ) { instructorName = name; // store the instructor's name } // end function setInstructorName // display a welcome message and the instructor's name void GradeBook::displayMessage() { // display a welcome message containing the course name cout << "Welcome to the grade book for\n" << getCourseName() << "!" << endl; /* write code to output the instructor's name */ } // end function displayMessage 逐行分析代码
10-17
<think>我们注意到用户输入中只有一个单词:constructor。这可能是用户想要了解JavaScript中构造函数的用法。 因此,我们将围绕JavaScript中的构造函数进行详细解释,包括ES5的函数构造函数和ES6的class语法中的constructor方法。 同时,我们会提供代码示例并解释。</think>### JavaScript 中的构造函数详解 在 JavaScript 中,`constructor` 是一个特殊的方法,用于创建和初始化类创建的对象。它扮演着以下关键角色: 1. **对象初始化**:在创建类实例时自动调用 2. **属性设置**:用于设置对象的初始状态 3. **继承基础**:在类继承中通过 `super()` 调用父类构造函数 #### 基础用法示例 ```javascript class Person { // 构造函数 constructor(name, age) { this.name = name; // 设置实例属性 this.age = age; console.log(`创建了 ${name} 实例`); } greet() { console.log(`你好,我是 ${this.name},今年 ${this.age} 岁`); } } // 实例化 const alice = new Person("Alice", 30); alice.greet(); // 输出: // 创建了 Alice 实例 // 你好,我是 Alice,今年 30 岁 ``` #### 继承中的构造函数 ```javascript class Employee extends Person { constructor(name, age, position) { super(name, age); // 必须首先调用父类构造函数 this.position = position; } work() { console.log(`${this.name} 担任 ${this.position} 职位`); } } const bob = new Employee("Bob", 25, "工程师"); bob.greet(); // 继承自Person bob.work(); // 输出: // 创建了 Bob 实例 // 你好,我是 Bob,今年 25 岁 // Bob 担任 工程师 职位 ``` #### 关键规则: 1. **必须的 super()**:在继承类中,访问 `this` 前必须先调用 `super()` 2. **默认构造函数**:如果没有显式定义,JS 会添加默认的空构造函数 3. **返回值**:构造函数不应返回任何值(返回原始值会被忽略,返回对象会替代实例) #### 构造函数 vs 普通方法 | 特性 | 构造函数 | 普通方法 | |------|----------|----------| | 调用方式 | 通过 `new` 关键字 | 通过实例调用 | | 目的 | 初始化对象状态 | 定义对象行为 | | 返回值 | 应返回 `undefined` | 可返回任意值 | | 命名 | 固定为 `constructor` | 自定义名称 | #### 高级用法:私有字段(ES2022+) ```javascript class SecureAccount { #balance = 0; // 私有字段 constructor(initialBalance) { this.#balance = initialBalance; } deposit(amount) { if (amount > 0) this.#balance += amount; } get balance() { return this.#balance; } } const account = new SecureAccount(100); account.deposit(50); console.log(account.balance); // 150 // console.log(account.#balance); // 报错:私有字段不可访问 ``` #### 常见错误处理 ```javascript class Parent { constructor() { this.value = 10; } } class Child extends Parent { constructor() { // 错误:未调用 super() 前访问 this // this.childValue = 20; // ReferenceError super(); // 正确位置 this.childValue = 20; } } const child = new Child(); console.log(child.value, child.childValue); // 10, 20 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值