C++构造和析构

简介: C++构造和析构

欢迎来观看温柔了岁月.c的博客

目前

设有C++学习专栏

C语言项目专栏

数据结构与算法专栏

目前主要更新C++学习专栏,C语言项目专栏不定时更新

待C++专栏完毕,会陆续更新C++项目专栏和数据结构与算法专栏

一周主要三更,星期三,星期五,星期天,
感谢大家的支持

构造函数

特点

1.名字和类名相同

2.没有返回值

3.构造函数是用来构造对象,构造对象时候,必定调用构造函数

4.不写构造函数,存在一个默认的构造函数,默认的构造函数是无参的,所以可以构造无参对象

5.默认的构造函数可以删掉,通过delete可以删除默认的构造函数

6.显示使用默认的构造函数,用defalt做显示调用

7.通常构造函数是public

8.如果自己写了构造函数,系统的默认构造函数就会不存在

9.构造函数决定对象的长相(构造函数有几个参数,构造的对象就要有几个参数)

10.构造函数通常做的事情,就是给数据成员初始化。

11.构造函数也是函数,可以进行重载,也可以进行缺省

12.通过缺省和重载,可以创建各种彰显不同的对象

#include<iostream>
#include<string>
using namespace std;
class MM
{
public:
  MM() = default; //显示使用默认构造函数
  MM() = delete;  //删除默认的构造函数
private:
  int age;
  string name;
};
int main()
{
  system("pause");
  return 0;
}

注意:如果一个类中的默认构造函数被删除的话,是不能够构造对象的。

构造函数的创建和使用

有参构造函数

#include<iostream>
#include<string>
using namespace std;
class MM
{
public:
  MM(int m_age, string m_name)
  {
    age = m_age;
    name = m_name;
  }
  void printDate()
  {
    cout << age << "\t" << name << endl;
  }
private:
  int age;
  string name;
};
int main()
{
  MM mm(10, "温柔了岁月");  //构造函数有2个参数,所以这路必须也要有两个参数,创建对象的过程就是调用构造函数过程
  mm.printDate();
  system("pause");
  return 0;
}

无参构造函数

#include<iostream>
#include<string>
using namespace std;
class MM
{
public:
  MM();  //无参构造函数
private:
  int age;
  string name;
};
int main()
{
  MM mm;
  system("pause");
  return 0;

关于new的构造函数

#include<iostream>
#include<string>
using namespace std;
class MM
{
public:
  MM();  //无参构造函数
  MM(int m_age, string m_name)
  {
    age = m_age;
    name = m_name;
  }
private:
  int age;
  string name;
};
int main()
{
  MM *p1 = new MM; //无参构造函数
  MM* p2 = new MM(18, "温柔了岁月"); //有参的构造函数
  system("pause");
  return 0;
}

析构函数

特点

1.~类名,当作析构函数的名称

2.没有参数

3.释放数据成员new的内存

在对象死亡前,自动调用

4.如果数据成员没有做new的操作,可以不写析构函数,不写析构函数,系统存在一个默认的析构函数

//析构函数
#include<iostream>
#include<cstring>
using namespace std;
class MM
{
public:
  MM(const char * str)
  {
    int length = strlen(str) + 1;
    name = new char[length];
    strcpy(name, str);
  }
  ~MM()
  {
    if (name != nullptr)
    {
      delete name;
      name = nullptr;
    }
    cout << "析构函数" << endl;
  }
private:
  char* name;
};
int main()
{
  MM* pmm = new MM("温柔了岁月");
  delete pmm;
  pmm = nullptr;  //立刻调用析构函数
  system("pause");
  return 0;
}

拷贝构造函数

特点

1.拷贝构造函数也是构造函数

2.拷贝构造函数的参数是固定的:对对象的引用

3.拷贝构造函数不写,会存在一个默认的拷贝构造函数

4.拷贝构造函数的作用:通过一个对象,创造另一个对象。

#include<iostream>
#include<string>
using namespace std;
class MM
{
public:
  MM(int m_age)
  {
    age = m_age;
  }
  //拷贝构造函数,通过传入对象属性,确定创建对象属性
  MM(MM& object)
  {
    age = object.age;
  }
  void printDate()
  {
    cout << age << endl;
  }
private:
  int age;
};
//函数传参也可以隐式调用
void print(MM object)
{
  object.printDate();
}
void Print(MM& object) //引用只是取别名,不调用拷贝构造函数,效率较高
{
  object.printDate();
}
int main()
{
  MM mm(10);
  //产生对象
  MM pmm = mm;  //隐式构造
  MM pm(mm); //显式构造
  print(mm); //隐式调用拷贝构造函数
  system("pause");
  return 0;
}

深拷贝和浅拷贝

浅拷贝:

没有在拷贝构造函数中,使用new

默认的拷贝构造函数都是浅拷贝

深拷贝:

在拷贝构造函数中做了new的操作

内存释放问题:

浅拷贝会导致同一段内存重复释放

//浅拷贝问题

#include<iostream>
#include<cstring>
using namespace std;
class MM
{
public:
  MM(const char* m_name)
  {
    name = new char[strlen(m_name) + 1];
    strcpy(name, m_name);
  }
   MM(MM& object)
  {
    name = object.name;
  }
  ~MM()
  {
    if (name != nullptr)
    {
      delete name;
      name = nullptr;
    }
  }
private:
  char* name;
};
int main()
{
  MM mm("温柔了岁月");
  MM pmm = mm;
  return 0;
}

delete把相同的两端数据都删除了,所以程序中断,浅拷贝的问题,要用深拷贝来解决。

解决方法

#include<iostream>
#include<cstring>
using namespace std;
class MM
{
public:
  MM(const char* m_name)
  {
    name = new char[strlen(m_name) + 1];
    strcpy(name, m_name);
  }
  MM(MM& object)
  {
    int length = strlen(object.name) + 1;
    name = new char[length];
    strcpy(name, object.name);
  }
  ~MM()
  {
    if (name != nullptr)
    {
      delete name;
      name = nullptr;
    }
  }
private:
  char* name;
};
int main()
{
  MM mm("温柔了岁月");
  MM pmm = mm;
  return 0;
}

一旦类中有指针,做了内存申请,并且对对象做了拷贝操作,就必须使用深拷贝

匿名对象

1.匿名对象就是无名对象,匿名对象只能充当右值,

2.如果做特殊处理,会直接死掉,要想对匿名对象赋初值,必须存在移动构造拷贝或者有const存在的普通拷贝构造。

#include<iostream>
using namespace std;
class MM
{
public:
  MM(int m_age)
  {
    age = m_age;
  }
  void printDate()
  {
    cout << age << endl;
  }
  MM(MM&& object)
  {
    age = object.age;
    cout << "调用移动构造" << age << endl;
  }
  ~MM()
  {
    cout << "析构函数" << endl;
  }
private:
  int age;
};
int main()
{
  MM(10);  //匿名对象没有名字
  MM girl = MM(10); //赋值对象, girl接管匿名对象的所有权
  girl.printDate();
  system("pasuse");
  return 0;
}

析构与构造调用的顺序

1 . 一般情况,构造顺序和析构顺序是相反的

2.全局和静态变量,最后释放的

3.delete会立刻调用析构函数

相关文章
|
30天前
|
C++
C++番外篇——对于继承中子类与父类对象同时定义其析构顺序的探究
C++番外篇——对于继承中子类与父类对象同时定义其析构顺序的探究
51 1
|
6月前
|
设计模式 编译器 C++
C++中的构造方法和析构方法详解
C++中的构造方法和析构方法详解
42 0
|
3月前
|
JavaScript Java C语言
面向对象编程(C++篇3)——析构
面向对象编程(C++篇3)——析构
29 2
|
3月前
|
JavaScript 前端开发 Java
面向对象编程(C++篇2)——构造
面向对象编程(C++篇2)——构造
31 0
|
5月前
|
C++ 容器
C++之deque容器(构造、赋值、大小、插入与删除、存取、排序)
C++之deque容器(构造、赋值、大小、插入与删除、存取、排序)
|
5月前
|
C++ 容器
C++字符串string容器(构造、赋值、拼接、查找、替换、比较、存取、插入、删除、子串)
C++字符串string容器(构造、赋值、拼接、查找、替换、比较、存取、插入、删除、子串)
|
6月前
|
编译器 C语言 C++
从C语言到C++_33(C++11_上)initializer_list+右值引用+完美转发+移动构造/赋值(中)
从C语言到C++_33(C++11_上)initializer_list+右值引用+完美转发+移动构造/赋值
35 1
从C语言到C++_33(C++11_上)initializer_list+右值引用+完美转发+移动构造/赋值(中)
|
6月前
|
存储 安全 C语言
从C语言到C++_33(C++11_上)initializer_list+右值引用+完美转发+移动构造/赋值(上)
从C语言到C++_33(C++11_上)initializer_list+右值引用+完美转发+移动构造/赋值
31 2
|
6月前
|
编译器 C语言 C++
从C语言到C++_33(C++11_上)initializer_list+右值引用+完美转发+移动构造/赋值(下)
从C语言到C++_33(C++11_上)initializer_list+右值引用+完美转发+移动构造/赋值
34 1
|
5月前
|
算法 C++ 容器
C++之vector容器操作(构造、赋值、扩容、插入、删除、交换、预留空间、遍历)
C++之vector容器操作(构造、赋值、扩容、插入、删除、交换、预留空间、遍历)
219 0