15.5.1构造函数的定义与使用
数据成员多为私有的,要对它们进行初始化,必须用一个公有函数来进行。同时这个函数应该在且仅在定义对象时自动执行一次。称为构造函数。
构造函数用途:
1)创建对象
2)初始化对象中的属性
3)类型转换。
构造函数是特殊的公有成员函数(在特殊用途中构造函数的访问限定可以定义成私有或保护),其特征如下:
- 
函数名与类名相同。 
- 
构造函数无函数返回类型说明。注意是没有而不是 void,即什么也不写,也不可写 void。实际上构造函数有返回值,返回的就是构造函数所创建的对象。 
- 
在程序运行时,当新的对象被建立,该对象所属的类构造函数自动被调用,在该对象生存期中也只调用这一次。 
- 
构造函数可以重载。严格地讲,类中可以定义多个构造函数,它们由不同的参数表区分,系统在自动调用时按一般函数重载的规则选一个执行。 
- 
构造函数可以在类中定义,也可以在类中声明,在类外定义。 
- 
如果类说明中没有给出构造函数,则 C++ 编译器自动给出一个缺省的构造函数:类名 (void) { }但只要我们定义了一个构造函数,系统就不会自动生成缺省的构造函数。只要构造函数是无参的或者只要各参数均有缺省值的,C++ 编译器都认为是缺省的构造函数,并且缺省的构造函数只能有一个。 
示例 1:编译器自动生成缺省构造函数
            
            
              cpp
              
              
            
          
          #include <iostream>
using namespace std;
class MyClass {
private:
    int num;
public:
    // 类中未定义任何构造函数,编译器自动生成缺省构造函数:MyClass(void) {}
    void show() {
        cout << "num: " << num << endl; // 内置类型成员num会被初始化为随机值(不同编译器行为可能不同)
    }
};
int main() {
    MyClass obj; // 调用编译器自动生成的缺省构造函数
    obj.show();
    return 0;
}示例 2:手动定义构造函数后,编译器不再生成缺省构造函数
            
            
              cpp
              
              
            
          
          #include <iostream>
using namespace std;
class MyClass {
private:
    int num;
public:
    // 手动定义了带参构造函数,编译器不再生成缺省构造函数
    MyClass(int n) {
        num = n;
    }
    void show() {
        cout << "num: " << num << endl;
    }
};
int main() {
    // MyClass obj; // 错误!编译器未生成缺省构造函数,无参构造方式被禁用
    MyClass obj(10); // 必须调用带参构造函数
    obj.show();
    return 0;
}示例 3:定义无参的缺省构造函数
            
            
              cpp
              
              
            
          
          #include <iostream>
using namespace std;
class MyClass {
private:
    int num;
public:
    // 手动定义无参构造函数,作为缺省构造函数
    MyClass() {
        num = 0; // 显式初始化成员
    }
    void show() {
        cout << "num: " << num << endl;
    }
};
int main() {
    MyClass obj; // 调用手动定义的无参缺省构造函数
    obj.show(); // 输出:num: 0
    return 0;
}示例 4:定义带缺省参数的构造函数(视为缺省构造函数)
            
            
              cpp
              
              
            
          
          #include <iostream>
using namespace std;
class MyClass {
private:
    int num;
public:
    // 带缺省参数的构造函数,视为缺省构造函数
    MyClass(int n = 0) {
        num = n;
    }
    void show() {
        cout << "num: " << num << endl;
    }
};
int main() {
    MyClass obj1;    // 调用缺省构造函数,num = 0
    MyClass obj2(5); // 调用带参构造函数,num = 5
    obj1.show();     // 输出:num: 0
    obj2.show();     // 输出:num: 5
    return 0;
}示例 5:缺省构造函数的唯一性(多个缺省构造会报错)
            
            
              cpp
              
              
            
          
          #include <iostream>
using namespace std;
class MyClass {
private:
    int num;
public:
    // 错误!定义了两个缺省构造函数(无参 + 全缺省参数),编译器会报"重定义"错误
    MyClass() {
        num = 0;
    }
    MyClass(int n = 0) {
        num = n;
    }
    void show() {
        cout << "num: " << num << endl;
    }
};
int main() {
    // MyClass obj; // 因构造函数重定义,编译失败
    return 0;
}15.5.2析构函数的定义与使用
当定义一个对象时,C++ 自动调用构造函数建立该对象并进行初始化,那么当一个对象的生命周期结束时,C++ 也会自动调用一个函数注销该对象并进行善后工作,这个特殊的成员函数即析构函数。
- 
函数名与类名相同,但在前面加上字符 ~,如:~CGoods()。
- 
析构函数无函数返回类型,与构造函数在这方面是一样的。但析构函数不带任何参数。 
- 
一个类有一个也只有一个析构函数,这与构造函数不同。 
- 
对象注销时,系统自动调用析构函数。 
- 
如果类说明中没有给出析构函数,则 C++ 编译器自动给出一个缺省的析构函数。如: ~类型名称(){}
示例 1:基础析构函数使用
            
            
              cpp
              
              
            
          
          #include <iostream>
using namespace std;
class MyClass {
public:
    // 构造函数:对象创建时调用
    MyClass() {
        cout << "构造函数调用,对象已创建" << endl;
    }
    // 析构函数:对象销毁时调用
    ~MyClass() {
        cout << "析构函数调用,对象已销毁" << endl;
    }
};
int main() {
    {
        MyClass obj; // 进入作用域,创建对象,调用构造函数
        // 此处 obj 处于生命周期内
    } // 离开作用域,对象销毁,自动调用析构函数
    return 0;
}示例 2:析构函数释放动态内存
            
            
              cpp
              
              
            
          
          #include <iostream>
using namespace std;
class MemoryDemo {
private:
    int* ptr; // 指向动态分配的内存
public:
    // 构造函数:申请堆内存
    MemoryDemo() {
        ptr = new int[10]; // 申请能存10个int的堆内存
        cout << "构造函数:申请了堆内存" << endl;
    }
    // 析构函数:释放堆内存
    ~MemoryDemo() {
        delete[] ptr; // 释放堆内存,避免内存泄漏
        cout << "析构函数:释放了堆内存" << endl;
    }
};
int main() {
    MemoryDemo* obj = new MemoryDemo(); // 动态创建对象
    delete obj; // 手动释放对象,触发析构函数
    return 0;
}示例 3:缺省析构函数的行为
#include <iostream>
using namespace std;
class DefaultDestructor {
private:
    int num;
public:
    DefaultDestructor() {
        num = 10;
        cout << "构造函数:num 初始化" << endl;
    }
    // 未定义析构函数,编译器自动生成缺省析构函数
};
int main() {
    DefaultDestructor obj;
    cout << "程序结束前,对象即将销毁" << endl;
    return 0;
}15.5.3总结
| 对比项 | 构造函数 | 析构函数 | 
|---|---|---|
| 作用 | 创建对象,初始化成员 / 分配资源 | 销毁对象,清理资源 | 
| 命名 | 与类名相同 | 与类名相同,前缀加 ~ | 
| 参数 | 可带参数,支持重载 | 无参数,不可重载 | 
| 调用时机 | 对象创建时 | 对象生命周期结束时 | 
| 缺省实现 | 无参空函数(未定义时生成) | 空函数(未定义时生成) | 
| 核心关注 | 初始化逻辑 | 资源释放逻辑 |