首页 > 编程语言 >c++的构造函数与析构函数

c++的构造函数与析构函数

时间:2024-09-08 23:54:57浏览次数:12  
标签:无参 调用 函数 与析构 c++ 析构 Student 构造函数

构造函数与析构函数

构造函数
1、什么构造函数

类、结构、联合中的特殊成员函数,与类名、结构名、联合名同的成员函数,没有返回值。

class 类名
{
public:
    类名(参数列表)
    {
        
    }
};
2、何时调用构造函数

当创建类对象时(实例化对象)会自动调用构造函数。

int main(int argc,const char* argv[])
{
    // 调用无参构造
    Student stu;
    Student* stup = new Student;
​
    // 调用有参构造
    Student stu1(10010,"hehe",'w',18,98);
    Student* stup1 = new Student(10011,"xixi",'m',20,95);
    
    // 调用有参构造,c11语法标准才支持,-std=c++11
    Student stu2 = {10010,"hehe",'w',18,98};
    return 0;
}
3、在构造函数中应该做什么

构造函数负责创建使用对象的环境,一般构造函数中负责:

1、给成员变量初始化

2、给指针成员分配内存

3、从文件、网络、数据库加载数据

4、完成一些准备工作

4、实现构造函数要注意的问题

在创建类对象时,一定会调用构造函数,如果类中没有显式实现构造函数,编译器会自动生成一个无参的什么都不做的构造函数。

如果显式实现了有参构造函数,那么编译器就不会再生成无参构造。

注意:在使用new[] 创建n个对象时,无法保证给所有的类对象都单独提供参数,去调用有参构造,那么必然需要调用无参构造,此时如果没有显式实现无参构造,编译就会出错。

方法1:

class Student
{
public:
    Student() {} // 极简无参构造
};

方法2:

给有参构造函数的所有成员都设置默认形参,当需要调用无参构造时,会自动使用默认参数调用有参构造。

// 无参构造未必无参
class Student
{
    ...
public:
    Student(int _id=0,const string& _name="",char _sex='w',short _age=0,float _score=0)
    {
        id = _id;
        name = _name;
        sex = _sex;
        age = _age;
        score = _score;
        cout << "我是有参构造" << endl;
    }
};
5、explicit关键字的作用

如果类中有单参的构造函数,那么它的参数类型数据就能隐藏提升为类对象,如果不使用该功能,可以在单参构造函数的前面加 explicit 关键字,参数类型数据就不能再隐藏提升为类对象。

总结:explicit关键字的作用就是禁止单参构造函数的类型提升功能。

#include <iostream>
using namespace std;

class Test
{
    int num;
public:
    [explicit] Test(int _num)
    {   
        num = _num;
    }    
};

void func(Test t)
{
    cout << "我被调用了" << endl;
}

int main(int argc,const char* argv[])
{
    func(1234);
}

析构函数:
1、什么析构函数

类、结构、联合中的特殊成员函数,在类名、结构名、联合的前面加~,就是析构函数,没有返回也没有参数。

struct Student
{
    int id; 
    string name;
    char sex;
    short age;
    float score;
public:
    Student(void)
    {
        cout << "我是无参构造函数" << endl;
    }
    Student(int _id,const string& _name,char _sex,short _age,float _score)
    {   
        id = _id;
        name = _name;
        sex = _sex;
        age = _age;
        score = _score;
        cout << "我是有参构造" << endl;
    }   
    ~Student(void)
    {   
        cout << "我是析构函数" << endl;
    }   
};
2、在析构函数中应该做什么

析构函数负责对象销毁时的收尾工作,一般构造函数中负责:

1、释放指针成员指向的堆内存

2、往文件中、数据库保存数据

3、何时调用析构函数

1、当类对象离开它所在的作用域时,系统会自动销毁类对象,并自动调用析构函数。

#include <iostream>
using namespace std;
​
struct Student
{
    int id;
    string name;
    char sex;
    short age;
    float score;
public:
    Student(void)
    {
        cout << "我是无参构造函数" << endl;
    }
    Student(int _id,const string& _name,char _sex,short _age,float _score)
    {
        id = _id;
        name = _name;
        sex = _sex;
        age = _age;
        score = _score;
        cout << "我是有参构造" << endl;
    }
    ~Student(void)
    {
        cout << "我是析构函数" << endl;
    }
};
​
int main(int argc,const char* argv[])
{
    do{
        // 当创建类对象时,自动调用构造函数,当对象离开它的作用域时,会自动调用析构函数
        Student stu;
    }while(0);
    cout << "-----------" << endl;
}

2、当使用delete或delete[] 释放堆内存上的类对象时,会自动调用析构函数(必须使用delete释放)。

#include <iostream>
using namespace std;
​
struct Student
{
    int id;
    string name;
    char sex;
    short age;
    float score;
public:
    Student(void)
    {
        cout << "我是无参构造函数" << endl;
    }
    Student(int _id,const string& _name,char _sex,short _age,float _score)
    {
        id = _id;
        name = _name;
        sex = _sex;
        age = _age;
        score = _score;
        cout << "我是有参构造" << endl;
    }
    ~Student(void)
    {
        cout << "我是析构函数" << endl;
    }
};
​
int main(int argc,const char* argv[])
{
​
    // 使用new 或 new[] 在堆内存上创建类对象时会自动调用构造函数
    Student* stup = new Student;
    Student* stus = new Student[10];
​
    // 类对象的个数,也是执行构造、析构函数的次数
    cout << *((int*)stus-1) << endl;
​
    // 使用delete 或 delete[] 释放堆内存上的类对象时会自动调用析构函数
    delete stup;
    delete[] stus;
​
    // 注意:使用new创建的就使用delete释放,使用new[]创建的就使用delete[]释放,不能混用
    return 0;
}
4、析构函数要注意的问题

如果没有显式实现析构函数,那么编译器会自动生成一个什么都不做的析构函数。

如果构造函数中使用new、malloc分配的堆内存,就一定要显式实现析构函数,并在析构函数中释放堆内存,否则就会造成内存泄漏。

标签:无参,调用,函数,与析构,c++,析构,Student,构造函数
From: https://blog.csdn.net/zzt_is_me/article/details/142035567

相关文章

  • [C++#33][异常] 错误码 | 抛出与捕获 | 异常安全 | 异常体系
    目录C语言与C++错误处理方式的对比及应用一、C语言传统的错误处理方式1.终止程序:assert2.返回错误码缺点:二、C++中的异常处理机制1.基本概念2.异常的抛出与捕获3.异常的重新抛出三、C++中的异常安全1.构造函数与析构函数的异常2.RAII(资源获取即初始化)3.使......
  • C++17: 用折叠表达式实现一个IsAllTrue函数
    前言让我们实现一个IsAllTrue函数,支持变长参数,可传入多个表达式,必须全部计算为true,该函数才返回true。本文记录了逐步实现与优化该函数的思维链,用到了以下现代C++新特性知识,适合对C++进阶知识有一定了解的人。这样一种从实际问题来学习和运用知识的过程还是挺有趣的,特此整理分......
  • C++笔记19•数据结构:红黑树(RBTree)•
    红黑树1.简介:    红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出俩倍,因而是接近平衡的。当搜索二叉树退化为单支树时,搜......
  • C++:类与对象
    一、面向对象编程(一)面向过程vs面向对象   面向过程(Procedural-Oriented-Programming, POP)和面向对象(Object-Oriented-Programming,OOP),是两种典型的编程范式,通常是作为划分编程语言的一大依据,在许多现代编程语言中都会有面向对象的编程范式,这是因为其与现实世界的良好......
  • C++宏
    宏是编译时预处理阶段用到的一种强大的工具,宏可以实现对指定代码片段的替换。依照笔者的理解,宏实际上是给某个特定的代码段起了一个别名。在预处理阶段,编译器将代码中的这个别名替换成相应的代码段。在C++当中,我们可以使用#define指令来定义宏。#definePI3.14159265358979......
  • C++变JAVE
    一、故事就是我今天闲的没事干,然后就突然想到了JAVE程序(就是我想到了用JAVE做菜单程序)然后就照着网上的教程然后就下载好了这个JDK-21#¥……&*&*O*&%……&K什么什么的东西,然后又让我在环境变量里修改一通后,他让我用下载地址打开cmd然后让我输入jave-version(不小心多打......
  • C++小游戏集合3个(不定时更新)1
    前言在Dvec++中想做游戏是很难的,但我不这么想,在下写了一些小游戏给客官看看一,2048#include<iostream>#include<vector>#include<ctime>#include<cstdlib>usingnamespacestd;classGame_2048{public:Game_2048();~Game_2048();voidintroduction()......
  • C++万字解析类和对象
     1.类的定义class为定义类的关键字,Stack为类的名字,{}中为类的主体,注意类定义结束时后面分号不能省略。类体中内容称为类的成员:类中的变量称为类的属性或成员变量;类中的函数称为类的方法或者成员函数。为了区分成员变量,一般习惯上成员变量会加一个特殊标识,如成员变量前面......
  • C++入门基础(内容太干,噎住了)
     文章目录1.缺省参数2.函数重载2.1重载条件:1.参数类型不同2.参数个数不同3.参数类型顺序不同 2.2不做重载条件情况:1.返回值相同时2.当全缺省遇见无参数3.引用3.1引用特性:3.2引用的使用1.缺省参数1.缺省参数是声明或定义函数时为函数的参数指定⼀个缺省值。......
  • C++ 模板类类型限定
    #include<iostream>#include<type_traits>usingnamespacestd;namespace{classIAnimal{public:virtualvoidsay()=0;};classDog:IAnimal{public:voidsay()override{......