一起来学习C++的构造和析构

目录
  • 1.构造函数
    • 1.1构造函数长什么样子
    • 1.2构造函数干嘛的
    • 1.3思考
  • 2.析构函数
    • 2.1析构函数长什么样子?
    • 2.2析构函数用来干嘛?(什么时候需要自己手动写析构函数)
  • 3.拷贝构造函数
    • 问题
  • 4.深浅拷贝
    • (1)浅拷贝:默认的拷贝构造叫做浅拷贝
    • (2)深拷贝:拷贝构造函数中做了new内存操作,并且做拷贝赋值的操作
  • 5.构造和析构顺序问题
  • 6.C++结构体
  • 答疑:
  • 总结

1. 构造函数

1.1 构造函数长什么样子

(1) 函数名和类名相同

(2) 没有返回值

(3) 如果不写构造函数,任何类中都存在一个默认的构造函数

I 默认的构造函数是无参的

II 当我们自己写了构造函数,默认的构造函数就不存在

(4) 构造函数在构造对象的时候调用

(5) delete可以用来删掉默认的函数

(6) 指定使用默认的无参构造函数,用default说明

(7) 允许构造函数调用另一个构造函数,只是要用初始化参数列表的写法

(8) 初始化参数列表 : 只有构造函数有

I 构造函数名(参数1,参数2,…):成员1(参数1),成员2(参数2),…{}

II 避免形参名和数据成员名相同的导致问题

1.2 构造函数干嘛的

(1) 构造函数用来构造对象

(2) 构造函数更多是用来初始化数据成员

1.3 思考

(1)为什么不写构造函数可以构造对象? 是因为存在一个默认的无参构造函数,所以可以构造无参对象

(2) 构造函数重载为了什么? 为了构造不同长相的对象。

#include <iostream>
using namespace std;
class MM
{
public:
	//MM() = delete;     删掉默认的构造函数
	MM(string mmName, int mmAge)
	{
		name = mmName;
		age = mmAge;
		cout << "带参构造函数" << endl;
	}
	//MM()
	//{
	//	cout << "无参构造函数" << endl;
	//}
	MM() = default;  //使用的是默认无参构造函数
	void print()
	{
		cout << name << " " << age << endl;
	}
protected:
	string name="Lisa";
	int age=18;
};
//为了能够构造不同长相的对象,我们会给构造函数缺省处理
class Boy
{
public:
	//Boy(string mname="", int mage=19)
	//{
	//	name = mname;
	//	age = mage;
	//}
	//上面函数 等效可以实现下面三个函数的功能
	Boy() {}
	Boy(string mName) { name = mName; }
	//出错:没有与之匹配的构造函数
	Boy(string mName, int mage) { name = mName; age = mage; }
protected:
	string name;
	int age;
};
//初始化参数列表的写法
string girlName = "Baby";
class  Student
{
public:
	Student(string mname="", int mage=18) :name(mname), age(mage)
	{
		cout << "初始化参数列表" << endl;
		//继承和类的组合必须采用初始化参数列表写法
	}
	Student(int mage) :name(girlName), age(mage) {}
protected:
	string name;
	int age;
};
//构造函数可以调用另一个构造函数初始化数据
class TT
{
public:
	TT(string name, int age) :name(name), age(age) {}
	//委托构造:允许构造函数调用另一个构造函数
	TT():TT("默认",18) {}     //没有给数据初始化
	void print()
	{
		cout << name << "\t" << age << endl;
	}
protected:
	string name;
	int age;
};
int main()
{
	//MM mm;     构造无参的对象,需要无参构造函数
	MM mm("mm", 28);
	mm.print();
	MM girl;
	girl.print();
	Boy boy1;
	Boy boy2("流浪之子");
	Boy boy3("王子", 18);
	TT  tt;
	tt.print();
	return 0;
}

2. 析构函数

2.1 析构函数长什么样子?

(1) 无返回值

(2) 无参数

(3) 函数名: ~类名

(4) 不写的话会存在默认的析构函数

(5) 析构函数不需要自己 调用,对象死亡的之前会调用析构函数

2.2 析构函数用来干嘛?(什么时候需要自己手动写析构函数)

(1) 当类中的数据成员是指针,并且动态申请内存就需要手写析构

(2) 析构函数用来释放数据成员申请动态内存

3. 拷贝构造函数

-> 拷贝构造函数也是构造函数,长相和构造函数一样的,只是参数是固定 .拷贝构造函数唯一的参数是对对象引用

-> 不写拷贝构造函数,也存在一个默认的拷贝构造函数

-> 拷贝构造函数作用: 通过一个对象去初始化另一个对象

问题

I 什么时候调用拷贝构造?

答:当通过一个对象去创建出来另一个新的对象时候需要调用拷贝

II 拷贝构造什么时候需要加const修饰参数?

答:当存在匿名对象赋值操作的时候,必须要const修饰

#include <iostream>
#include <string>
using namespace std;
class MM
{
public:
	MM() = default;
	MM(string name, int age) :name(name), age(age) {}
	void print()
	{
		cout << name << "\t" << age << endl;
	}
	//拷贝构造
	MM(const MM& mm)			 //MM girl(mm);
	{
		name = mm.name;  //girl.name=mm.name
		age = mm.age;	 //girl.age=mm.age
		cout << "拷贝构造" << endl;
	}

protected:
	string name;
	int age;
};
void printData(MM mm)   //MM mm=实参;
{
	mm.print();
}
void printData2(MM& mm) //不存在拷贝本
{
	mm.print();
}
int main()
{
	MM mm("mm", 18);
	mm.print();
	//显示调用调用
	cout << "显示调用调用" << endl;
	MM girl(mm);        //通过一个对象创建另一个对象
	girl.print();
	//隐式调用
	cout << "隐式调用" << endl;
	MM girl2 = mm;		//拷贝构造
	girl2.print();
	MM girl3;
	girl3 = mm;			//运算符重载
	girl3.print();
	//函数传参
	cout << "第一种调用形态" << endl;
	printData(mm);
	cout << "第二种调用形态" << endl;
	printData2(mm);
	//无名对象 匿名对象
	MM temp;
	temp = MM("匿名", 18);
	temp.print();
	//匿名对象创建对象时候,拷贝构造一定要用const修饰
	MM temp2 = MM("匿名", 199);
	return 0;
}

4. 深浅拷贝

(1)浅拷贝: 默认的拷贝构造叫做浅拷贝

(2)深拷贝: 拷贝构造函数中做了new内存操作,并且做拷贝赋值的操作

#include<iostream>
#include <cstring>
#include <string>
using namespace std;
class MM
{
public:
	MM(const char* mname, int age) :age(age)
	{
		name = new char[strlen(mname) + 1];
		strcpy_s(name, strlen(mname) + 1, mname);
	}
	void print()
	{
		cout << name << "\t" << age << endl;
	}
	MM(const MM& object)
	{
		//name = object.name;
		name = new char[strlen(object.name) + 1];
		strcpy_s(name, strlen(object.name) + 1, object.name);
		//name = object.name;
		age = object.age;
	}
	~MM()
	{
		delete[] name;
	}
protected:
	char* name;
	int age;
};
int main()
{
	{
		MM mm("baby", 19);
		MM girl(mm);
		MM gm = mm;
		mm.print();
		girl.print();
		gm.print();
	}
	return 0;
}

5. 构造和析构顺序问题

(1)普通对象,构造顺序和析构顺序是相反

(2)new出来的对象,delete会直接调用析构函数

(3)static对象,当程序关闭的时候,生命周期才结束,所以是最后释放

#include <iostream>
#include <string>
using namespace std;
class MM
{
public:
	MM(string name="x") :name(name) {
		cout << name;
	}
	~MM(){
		cout << name;
	}
protected:
	string name;
};
int main()
{
	{
		MM mm1("A");			//A
		static MM mm2("B");		//B   程序关闭时候才死亡,最后析构
		MM* p3 = new MM("C");	//C
		MM mm4[4];				//xxxx
		delete p3;				//C  delete 直接调用析构
		p3 = nullptr;
								//xxxxAB
	}
	//ABCxxxxCxxxxAB
	return 0;
}

6. C++结构体

#include <iostream>
#include <string>
using namespace std;
struct MM
{
	//默认为公有属性
	//类中默认属性是私有属性
//protected:
	string name;
	int age;
public:
	MM(string name) :name(name)
	{
		cout << "构造函数" << endl;
	}
	MM(const MM& object)
	{
		name = object.name;
		age = object.age;
		cout << "拷贝构造" << endl;
	}
	~MM()
	{
	}
};
int main()
{
	//采用创建时候赋值的方式,也是调用构造函数
	//MM object = { "lisa",19 };  错误,因为没有两个参数的构造函数
	MM  object = { "lisa" };
	cout << object.name << "\t" << object.age << endl;
	//C++结构体一旦写了构造函数,就必须按照C++类的方式的去用
	MM mm(object);
	cout << mm.name << "\t" << mm.age << endl;
	return 0;
}

答疑:

  • 为什么要手动写析构函数? 因为默认的不会释放数据成员动态申请的内存
  • 函数名和类型相同函数叫做构造函数
  • 函数名字是~类名的无参函数叫做析构函数
  • 以对象的引用为参数的构造函数叫做拷贝构造函数(复制构造函数)
  • 怎么写出来,默认的构造函数,就是那种在没有传参的时候的那一串垃圾值
class Boy
{
public:
	Boy() {}
	void print()
	{
		cout << a << "\t" << b << "\t" << c << endl;
	}
protected:
	int a;
	int b;
	int c;
};
int main()
{
    return 0;
}

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • C++踩坑实战之构造和析构函数

    目录 前言 构造函数 通过构造函数实现的类型转换 派生类的构造函数 析构函数 继承中的析构函数 应用 总结 前言 我是练习时长一年的 C++ 个人练习生,喜欢野指针.模板报错和未定义行为(undefined behavior).之前在写设计模式的『工厂模式』时,一脚踩到了构造.继承和 new 组合起来的坑,现在也有时间来整理一下了. 构造函数 众所周知:在创建对象时,防止有些成员没有被初始化导致不必要的错误,在创建对象的时候自动调用构造函数(无声明类型),完成成员的初始化.即: Class c

  • C++中构造函数与析构函数的详解及其作用介绍

    目录 构造函数 默认构造函数 有参构造函数 析构函数 析构函数例子 析构函数执行时机 局部对象 全局对象 构造函数 构造函数 (constructor) 是一种特殊的成员函数. 它会在每次创建类的新对象时执行. 构造函数的名称与类的名称是完全相同的, 并且不会返回任何类型. 构造函数可用于为某些成员变量设置初始值. 格式: Class::Class(); // 构造函数 默认构造函数 如果用户自己没有定义构造函数, C++ 系统会自动生成一个默认构造函数. 这个构造函数体是空的, 没有参数, 不

  • C++:构造函数,析构函数详解

    目录 前言 一.面向对象 二.构造函数 1.基本概念 2.构造函数重载 1.构造函数分类 2.有参构造函数: 3.有参构造函数3个调用规则: 4.拷贝构造函数 5.析构函数 总结 前言 上期了解C++类中有public.protected.private三种访问权限. 肯定会有人疑惑,C++为什么要设置这三个权限呢 本期内容就是围绕上面的问题展开说明 一.面向对象 开始的文章就提到过,类是(OOP)面向对象编程的基础 那么面向对象编程究竟是个什么东东呢 百度百科是这样解释的 通俗的来说就是利用代

  • C++继承中的对象构造与析构和赋值重载详解

    目录 一.构造/析构顺序及继承性 二.拷贝构造的继承性 三.赋值重载不具有继承性 总结 一.构造/析构顺序及继承性 class A { private: int _a; public: A(int a = 0): _a(a) { cout << "A()" << this << endl; } ~A() { cout << "~A()"<< this <<endl; } }; class B :

  • c++ 入门——浅析构造函数和析构函数

    前文回顾 本文档环境基于Vscode + GCC + CodeRunner 关于C++的环境搭建请参考下面链接: https://www.jb51.net/article/186542.htm 由于本人具有C#开发经验,部分相同的知识就不再赘述了.只列一下需要记录的知识. HelloWorld cout 代表输出<< cin 代表输入 >> endl;代表换行,清空缓冲区. #include <iostream> int main() { std::cout <&

  • C++编程析构函数拷贝构造函数使用示例详解

    目录 构造函数 析构函数 拷贝构造之深拷贝和浅拷贝 深浅拷贝区别 首先定义一个类进行操作. class MM { public: protected: int year; string name; } 构造函数在类中默认有一个无参的构造函数 默认的构造函数为 类名(){}:这个构造函数 如果直接写了构造函数那么这个构造函数将会没有 构造函数 class MM { public: //MM() {};//无参构造函数 MM(int year, string name) :year(year), n

  • 一起来学习C++的构造和析构

    目录 1.构造函数 1.1构造函数长什么样子 1.2构造函数干嘛的 1.3思考 2.析构函数 2.1析构函数长什么样子? 2.2析构函数用来干嘛?(什么时候需要自己手动写析构函数) 3.拷贝构造函数 问题 4.深浅拷贝 (1)浅拷贝:默认的拷贝构造叫做浅拷贝 (2)深拷贝:拷贝构造函数中做了new内存操作,并且做拷贝赋值的操作 5.构造和析构顺序问题 6.C++结构体 答疑: 总结 1. 构造函数 1.1 构造函数长什么样子 (1) 函数名和类名相同 (2) 没有返回值 (3) 如果不写构造函数

  • Python类方法__init__和__del__构造、析构过程分析

    最近学习<Python参考手册>学到Class部分,遇到了类的构造析构部分的问题: 1.什么时候构造? 2.什么时候析构? 3.成员变量如何处理? 4.Python中的共享成员函数如何访问? ------------------------ 探索过程: 1.经过查找,Python中没有专用的构造和析构函数,但是一般可以在__init__和__del__分别完成初始化和删除操作,可用这个替代构造和析构.还有一个__new__用来定制类的创建过程,不过需要一定的配置,此处不做讨论. 2.类的成员函

  • C++类的构造与析构特点及作用详解

    目录 一.类的构造函数 什么是构造函数 构造函数的特点 构造函数的作用 二.类的析构函数 什么是析构函数 析构函数的特点 小结 析构函数的作用 总结 构造函数 析构函数 一.类的构造函数 什么是构造函数 和类具有相同名称,并且没有返回值类型的函数,就是类的构造函数 概念模糊.直接举例: #include <stdio.h> #include <windows.h> struct Test { Test() // 和类具有相同的名.并且没有返回值 { } }; int main()

  • php学习笔记 面向对象的构造与析构方法

    复制代码 代码如下: <?php /* * 1.对象中成员的访问(在一个对象的内部方法中,去访问本对轩昂中的其他方法和成员属性) * 2.在对象中的方法中都默认有一个$this关键字,这个关键字代表调用这个方法的对象 * * 构造方法 * * 1.是对象创建完成后,"第一个""自动调用"的方法 * * 2.构造方法的定义,方法名是一个固定的, * 在php4中:和类名相同的方法就是构造方法 * 在php5中:构造方法选择使用 魔术方法__construct()

  • C++关于类结构体大小和构造顺序,析构顺序的测试详解

    目录 总结 #include <iostream> using namespace std; /** 1. c++的类中成员若不加修饰符的话,默认是private 2. 调用构造函数时,先递归调用最顶级的父类构造函数,再依次到子类的构造函数. 3. 调用析构函数时相反,先调用最底层的子类析构函数,再依次到父类的构造函数. 4. 空类的sizeof(A)大小为1,多个空类继承后的子类大小也是1 */ class A{ public: A() { cout<<"A const

  • C++构造析构赋值运算函数应用详解

    目录 了解C++默默编写哪些函数 不想使用编译器函数 为多态基类声明virtual析构函数 别让异常逃离析构函数 绝不在构造和析构过程中调用virtual函数 令operator=返回一个reference to *this 在operator=中处理自我赋值 复制对象时别忘了每个成分 了解C++默默编写哪些函数 当实现一个空类,c++会为你补上构造函数,拷贝构造函数,拷贝赋值运算符,析构函数 class Empty{}; //等于你写了 class{ public: Empty(){...};

  • 完全掌握C++编程中构造函数使用的超级学习教程

    构造函数是一种可初始化其类的实例的成员函数.构造函数具有与类相同的名称,没有返回值.构造函数可以具有任意数量的参数,类可以具有任意数量的重载构造函数.构造函数可以具有任何可访问性(公共.受保护或私有).如果未定义任何构造函数,则编译器会生成不采用任何参数的默认构造函数:可以通过将默认构造函数声明为已删除来重写此行为. 构造函数顺序 构造函数按此顺序执行工作: 按声明顺序调用基类和成员构造函数. 如果类派生自虚拟基类,则会将对象的虚拟基指针初始化. 如果类具有或继承了虚函数,则会将对象的虚函数指针

  • C++的虚析构详解及实例代码

    C++的虚析构 最近准备复习一遍所有的知识点,先从基础开始做起,用几分钟写个继承和析构吧. 父类为A,子类为B,代码如下: class A { public: A() { cout << "构造A"<< endl; } ~A() { cout << "析构A" << endl; } } class B:public A { public: B() { cout << "构造B"<&

  • C++中的new/delete、构造/析构函数、dynamic_cast分析

    1,new 关键字和 malloc 函数区别(自己.功能.应用): 1,new 关键字是 C++ 的一部分: 1,如果是 C++ 编译器,则肯定可以用 new 申请堆空间内存: 2,malloc 是由 C 库提供的函数: 1,如果没有相应的库,malloc 将不能使用: 2,有些特殊的嵌入式开发中,少了 C 库,则就不能动态内存分配: 3,new 以具体类型为单位进行内存分配: 1,面向对象中一般用 new,不用 malloc: 4,malloc 以字节为单位进行内存分配: 5,new 在申请内

随机推荐