06-析构函数和构造函数

析构函数

创建对象时系统会自动调用构造函数进行初始化工作,同样,销毁对象时系统也会自动调用一个函数来进行清理工作,例如释放分配的内存、关闭打开的文件等。

特点

析构函数是一种特殊的成员函数,没有返回值,是在销毁对象时自动执行。构造函数的名字和类名相同,而析构函数的名字是在类名前面加一个~符号。析构函数不允许有参数 ,不可以发生重载。

构造函数

用途:

构造函数主要作用在于创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无须手动调用。

析构函数主要用于对象销毁前系统自动调用,执行一些清理工作。

基本语法:

ClassName(){}

特点

  1. 不需要返回值不用写void。
  2. 构造函数名称 与 类名 相同的 。
  3. 允许有参数,可以发生函数重载。

代码示例

#include <iostream>
/**
 * 构造函数和析构函数
 */
using namespace std;

class Person{
public:
    // 构造函数和析构函数必须要写到公共权限下面
    Person(){
        cout << "Person的构造函数调用" << endl;
    }
    
    // 析构函数
    ~Person(){
        cout << "Person的析构函数调用" << endl;
    }
};

void test01(){
    // 创建对象
    Person p;

    /*
    构造函数由编译器自动调用一次,无须手动调用
    如果我们不提供构造函数,编译器也会自动提供构造函数,默认空实现.
    */

    // 析构函数 也是编译器自动调用一次
    // 如果我们不提供析构函数,编译器会提供空实现析构函数
    // 析构函数 在对象被销毁前 自动调用
}
int main() {
    cout << "Hello, World!" << endl;

    // 调用函数
    test01();
    return 0;
}
构造函数调用

构造函数的分类

1、按参数可分为:无参构造(默认构造) 、带参构造

2、按类型可分为:拷贝构造、普通构造。

代码示例

#include <iostream>
using namespace std;

// 创建学生类
class Student{
public:
    // 定义变量
    int age;

    Student(){
        cout << "Student的默认构造函数调用" << endl;
    }

    Student(int a){
        cout << "Student的有参构造函数调用" << endl;
    }

    // 拷贝构造,值传递的本质就是调用拷贝构造函数
    Student(const Student &stu){
        cout << "Student的拷贝构造函数调用" << endl;
        age = stu.age;
    }

    ~Student(){
        cout << "Student的析构函数调用" << endl;
    }
};

// 构造函数的调用
void test01(){
    // 默认构造函数的调用
    Student stu;

}

/**
 * 调用方法
 * @return
 */

void test02(){
    /**
     * 括号法
     */

     /*
     Student stu(10); // 有参构造
     stu.age = 16;

     // 调用拷贝构造函数
     Student stu1(stu);
     cout << "stu1的年龄是:"<< stu1.age << endl;
      */

    // 注意:不要利用括号法,调用默认构造函数 Student stu(); 将代码看成函数的声明而不是认为是在创建对象。

    /**
     * 显示法
     */

     /*
     Student stu3 = Student(10); // 有参构造调用
     Student stu4 = Student(stu3); // 显示法调用拷贝构造函数
     */

     // 匿名对象
     // Student(10); // 单独写Student(10),被称为匿名对象,特点:当本行执行完毕,立即释放。
     // 不要利用拷贝构造函数,初始化匿名对象。

     // 隐式转换法 可读性低
     Student stu5 = 10; // 编译器隐式将代码转换为 Student stu = Student(10);
     // 利用隐式转换法,调用拷贝构造函数
     Student stu6 = stu5; // 隐式转为student stu6 = Student(stu5);

}
int main() {
    cout << "Hello, World!" << endl;
    // 调用函数
    // test01();

    test02();
    return 0;
}
拷贝构造函数的调用时机

方式一:

对象以值传递的方式传给函数参数

方式二:

函数局部对象以值传递的方式从函数返回.

方式三:

用一个对象初始化另一个对象

代码示例

#include <iostream>
/**
 * 拷贝构造函数的调用时机
 */
using namespace std;

// 创建学生类
class Student{
public:
    // 定义变量
    int age;

    Student(){
        cout << "Student的默认构造函数调用" << endl;
    }

    Student(int a){
        cout << "Student的有参构造函数调用" << endl;
    }

    // 拷贝构造,值传递的本质就是调用拷贝构造函数
    Student(const Student &stu){
        cout << "Student的拷贝构造函数调用" << endl;
        age = stu.age;
    }

    ~Student(){
        cout << "Student的析构函数调用" << endl;
    }
};

// 1.用已经创建好的对象初始化新的对象
void test01(){
    Student stu;
    stu.age = 19;

    // 拷贝构造函数调用
    Student stu2(stu);
    cout << "stu2的年龄是:" << stu2.age << endl;
}

// 2.值传递的方式 给函数参数传值
void doStudy(Student stu){}

void test02(){
    // 创建对象
    Student stu;
    doStudy(stu);
}

// 3、以值的方式返回局部变量
Student doStudy2(){
    Student stu;
    return stu;
}

void test03(){
    Student stu = doStudy2();
}

int main() {
    cout << "Hello, World!" << endl;
    // 调用函数
    // test01();

    // test02();
    test03();
    return 0;
}
构造函数调用规则

默认情况下,c++编译器至少为我们写的类增加3个函数。

1.默认构造函数(无参,函数体为空)。

2.默认析构函数(无参,函数体为空)。

3.默认拷贝构造函数,对类中非静态成员属性简单值拷贝。

注意点:

1、如果定义拷贝构造函数,c++不会再提供任何默认构造函数。
2、如果定义了普通构造(非拷贝),c++不在提供默认无参构造,但是会提供默认拷贝构造。

深拷贝和浅拷贝

浅拷贝

定义:同一类型的对象之间可以赋值,使得两个对象的成员变量的值相同,两个对象仍然是独立的两个对象,这种情况被称为浅拷贝。

一般情况下,浅拷贝没有任何副作用,但是**当类中有指针,并且指针指向动态分配的内存空间,析构函数做了动态内存释放的处理,会导致内存问题**。

深拷贝

当类中有指针,并且此指针有动态分配空间,析构函数做了释放处理,往往需要自定义拷贝构造函数,自行给指针动态分配空间。

代码示例

#include <iostream>
#include <cstring>
/**
 * 深拷贝与浅拷贝
 */
using namespace std;

// 创建Person类
class Person{
public:
    // 定义成员变量
    char * myName;
    int myAge;

    // 代参构造
    Person(char * name, int age){
        // 给Person的name,age开辟堆空间
        myName = (char *)malloc(strlen(name) + 1);
        strcpy(myName, name);
        myAge = age;
    }

    //自己提供拷贝构造函数,实现深拷贝
    Person(const Person &p){
        myAge = p.myAge;
        myName = (char *)malloc(strlen(p.myName) + 1);
        // 复制
        strcpy(myName, p.myName);
    }

    // 析构函数
    ~Person(){ // 释放在堆空间开辟的属性
        cout << "Person析构函数被调用" << endl;
        // 条件判断
        if(myName != NULL){
            free(myName);
            myName = NULL;
        }
    }
};

// 声明函数
void test01(){
    Person p1("curry", 10);
    cout << "p1的姓名:" << p1.myName << "年龄:"<<p1.myAge <<endl;

    // 调用拷贝构造函数
    Person p2 = p1; // 初始化p2对象
    cout << "p2的姓名:" << p2.myName << "年龄:" << p2.myAge << endl;
}
int main() {
    cout << "Hello, World!" << endl;
    test01();
    return 0;
}

explicit关键字

c++提供了关键字explicit,禁止通过构造函数进行的隐式转换。声明为explicit的构造函数不能在隐式转换中使用。

explicit注意

  • explicit用于修饰构造函数,防止隐式转化。
  • 是针对单参数的构造函数(或者除了第一个参数外其余参数都有默认值的多参构造)而言。

代码示例

#include <iostream>
/**
 * explicit关键字的意义
 */
using namespace std;
 class MyString{
 public:
     explicit MyString(int len){
         cout << "MyString有参构造函数(int )调用" << endl;
     }
     MyString(char * str){
         cout << "MyString有参构造函数(char *)调用" << endl;
     }
 };

 // 调用函数
 void test(){
     MyString str = "kobe is mvp";
     MyString str1 = MyString("curry is child");

     MyString str2 = MyString(10);
 }
int main() {
    // 调用函数
    test();
    return 0;
}

代码运行结果

MyString有参构造函数(char *)调用
MyString有参构造函数(char *)调用
MyString有参构造函数(int )调用
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: C++面向对象编程中,构造函数析构函数是两个非常重要的概念。 构造函数是一种特殊的函数,它在对象被创建自动调用,用于初始化对象的数据成员。构造函数的名称与类名相同,没有返回值类型,可以有参数,可以有多个构造函数,以便在创建对象进行不同的初始化操作。 析构函数是一种特殊的函数,它在对象被销毁自动调用,用于清理对象的资源。析构函数的名称与类名相同,前面加上一个波浪号(~),没有返回值类型,不接受任何参数。 构造函数析构函数是C++面向对象编程中的两个重要概念,它们的作用是初始化对象和清理对象的资源,是面向对象编程的基础。 ### 回答2: 面向对象是一种程序设计的方法,它以对象为中心,通过封装、继承和多态等机制来组织和管理代码,使程序更加可靠、可重用和易于维护。其中,构造函数析构函数是面向对象程序设计中的重要概念。 构造函数是一种特殊的成员函数,它在对象创建自动调用,用于对对象进行初始化。构造函数的名称与类名相同,没有返回值,可以重载,可以带参数,也可以不带参数。构造函数的作用是保证对象在创建始终处于一种可靠的状态,从而避免程序运行的错误和异常。 析构函数是与构造函数相对应的一种成员函数,它在对象销毁自动调用,用于对对象进行善后处理。析构函数的名称与类名相同,前面加上一个波浪号(~),没有参数,也没有返回值。析构函数的作用是释放对象所占用的资源,例如动态分配的内存、打开的文件、建立的连接等,在对象销毁之前要确保这些资源已经被回收,从而避免内存泄漏和资源浪费。 构造函数析构函数是面向对象程序设计中的重要组成部分,它们体现了对象的生命周期和和管理方式,尤其是在涉及到动态内存分配和释放更为重要。正确使用构造函数析构函数可以提高程序的可靠性、可重用性和可维护性,从而更好地实现程序模块化和复用。因此,在面向对象程序设计中,构造函数析构函数应该被视为重要的设计关注点,特别是在涉及到大型程序或长期运行的系统。 ### 回答3: 面向对象编程是一种广泛使用的编程范式,它关注的是对象的行为和属性,而不是函数和逻辑。构造函数析构函数是面向对象编程中的两个重要概念,在类的实例化和释放过程中起到了关键的作用。 构造函数是一个类的特殊函数,它习惯性地与类名相同,用于初始化类的实例。构造函数可以接收参数,这些参数可以用来初始化类的成员变量。每当一个新的对象被创建构造函数自动调用,以确保对象被正确地初始化。如果类没有定义构造函数,编译器将提供一个默认构造函数析构函数是一个类的另一个重要函数,它也习惯性地与类名相同,用于释放由该类创建的资源。析构函数通常用于释放内存、关闭打开的文件、关闭网络连接等等,以防止资源泄漏和造成程序崩溃。当一个对象被删除或销毁析构函数自动调用,以确保类能够正确地清理资源。 需要注意的是,当一个对象被复制,也调用构造函数析构函数。使用深拷贝和浅拷贝来管理类的复制,以确保不复制对象的私有数据。此外,有一些 C++ 特殊语法,如移动语义和智能指针等等,可以用于提高构造函数析构函数的效率和安全性。 总之,构造函数析构函数是面向对象编程中不可或缺的两个概念。它们可以保证类的正确初始化和释放,从而防止资源泄漏和程序崩溃。编写好构造函数析构函数是编写高质量 C++ 代码的关键。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值