完全弄懂C++中的构造与析构函数

类的构造函数
带参数的构造函数
使用初始化列表来初始化字段
类的析构函数
构造函数与析构函数的特点
显式调用析构函数
拷贝构造函数
类的构造函数
类的构造函数是类的一种特殊的成员函数,它会在每次创建类的新对象时执行。
构造函数的名称与类的名称是完全相同的,并且不会返回任何类型,也不会返回 void。构造函数可用于为某些成员变量设置初始值。 推荐群:C++大学技术协会:145655849
下面的实例有助于更好地理解构造函数的概念:

#include

using namespace std;

class CLine
{
public:
void setLength(double len);
double getLength(void);
CLine(); // 这是构造函数

private:
double m_dblength;
};

// 成员函数定义,包括构造函数
CLine::CLine(void)
{
cout << “Object is being created” << endl;
}

void CLine::setLength(double len)
{
m_dblength = len;
}

double CLine::getLength(void)
{
return m_dblength;
}
// 程序的主函数
int main(int argc, char* argv[])
{
CLine line;

// 设置长度
line.setLength(6.0);
cout << "Length of line : " << line.getLength() << endl;system("pause");
return 0;

}
xxxxxxxxxx42 1#include 2​3using namespace std;4​5class CLine6{7public:8 void setLength(double len);9 double getLength(void);10 CLine(); // 这是构造函数11​12private:13 double m_dblength;14};15​16// 成员函数定义,包括构造函数17CLine::CLine(void)18{19 cout << “Object is being created” << endl;20}21​22void CLine::setLength(double len)23{24 m_dblength = len;25}26​27double CLine::getLength(void)28{29 return m_dblength;30}31// 程序的主函数32int main(int argc, char* argv[])33{34 CLine line;35​36 // 设置长度37 line.setLength(6.0);38 cout << "Length of line : " << line.getLength() << endl;39​40 system(“pause”);41 return 0;42}

带参数的构造函数
默认的构造函数没有任何参数,但如果需要,构造函数也可以带有参数。这样在创建对象时就会给对象赋初始值,如下面的例子所示:

#include

using namespace std;

class CLine
{
public:
void setLength(double len);
double getLength(void);
CLine(double len); // 这是构造函数

private:
double m_dblength;
};

// 成员函数定义,包括构造函数
CLine::CLine(double len)
{
cout << "Object is being created, length = " << len << endl;
m_dblength = len;
}

void CLine::setLength(double len)
{
m_dblength = len;
}

double CLine::getLength(void)
{
return m_dblength;
}
// 程序的主函数
int main(int argc, char* argv[])
{
CLine line(10.0);

// 获取默认设置的长度
cout << "Length of line : " << line.getLength() << endl;
// 再次设置长度
line.setLength(6.0);
cout << "Length of line : " << line.getLength() << endl;system("pause");
return 0;

}
xxxxxxxxxx45 1#include 2​3using namespace std;4​5class CLine6{7public:8 void setLength(double len);9 double getLength(void);10 CLine(double len); // 这是构造函数11​12private:13 double m_dblength;14};15​16// 成员函数定义,包括构造函数17CLine::CLine(double len)18{19 cout << "Object is being created, length = " << len << endl;20 m_dblength = len;21}22​23void CLine::setLength(double len)24{25 m_dblength = len;26}27​28double CLine::getLength(void)29{30 return m_dblength;31}32// 程序的主函数33int main(int argc, char* argv[])34{35 CLine line(10.0);36​37 // 获取默认设置的长度38 cout << "Length of line : " << line.getLength() << endl;39 // 再次设置长度40 line.setLength(6.0);41 cout << "Length of line : " << line.getLength() << endl;42​43 system(“pause”);44 return 0;45}

使用初始化列表来初始化字段
使用初始化列表来初始化字段:

CLine::CLine( double len): m_dblength(len)
{
cout << "Object is being created, length = " << len << endl;
}
xxxxxxxxxx4 1CLine::CLine( double len): m_dblength(len)2{3 cout << "Object is being created, length = " << len << endl;4}

上面的语法等同于如下语法:

CLine::CLine( double len)
{
m_dblength = len;
cout << "Object is being created, length = " << len << endl;
}
xxxxxxxxxx5 1CLine::CLine( double len)2{3 m_dblength = len;4 cout << "Object is being created, length = " << len << endl;5}

假设有一个类 CVolume,具有多个字段 X、Y、Z 等需要进行初始化,同理地,您可以使用上面的语法,只需要在不同的字段使用逗号进行分隔,如下所示:

CVolume::CVolume( double a, double b, double c): X(a), Y(b), Z©
{

}
xxxxxxxxxx4 1CVolume::CVolume( double a, double b, double c): X(a), Y(b), Z©2{3 …4}

类的析构函数
类的析构函数是类的一种特殊的成员函数,它会在每次删除所创建的对象时执行。
析构函数的名称与类的名称是完全相同的,只是在前面加了个波浪号(~)作为前缀,它不会返回任何值,也不能带有任何参数。析构函数有助于在跳出程序(比如关闭文件、释放内存等)前释放资源。
下面的实例有助于更好地理解析构函数的概念:

#include

using namespace std;

class CLine
{
public:
void setLength(double len);
double getLength(void);
CLine(); // 这是构造函数声明
~CLine(); // 这是析构函数声明

private:
double m_dblength;
};

// 成员函数定义,包括构造函数
CLine::CLine(void)
{
cout << “Object is being created” << endl;
}
CLine::~CLine(void)
{
cout << “Object is being deleted” << endl;
}

void CLine::setLength(double len)
{
m_dblength = len;
}

double CLine::getLength(void)
{
return m_dblength;
}
// 程序的主函数
int main()
{
CLine line;

// 设置长度
line.setLength(6.0);
cout << "Length of line : " << line.getLength() << endl;//system("pause");
return 0;

}
xxxxxxxxxx47 1#include 2​3using namespace std;4​5class CLine6{7public:8 void setLength(double len);9 double getLength(void);10 CLine(); // 这是构造函数声明11 ~CLine(); // 这是析构函数声明12​13private:14 double m_dblength;15};16​17// 成员函数定义,包括构造函数18CLine::CLine(void)19{20 cout << “Object is being created” << endl;21}22CLine::~CLine(void)23{24 cout << “Object is being deleted” << endl;25}26​27void CLine::setLength(double len)28{29 m_dblength = len;30}31​32double CLine::getLength(void)33{34 return m_dblength;35}36// 程序的主函数37int main()38{39 CLine line;40​41 // 设置长度42 line.setLength(6.0);43 cout << "Length of line : " << line.getLength() << endl;44​45 //system(“pause”);46 return 0;47}

构造函数与析构函数的特点
对于构造函数而言:

与类同名
没有返回值
会在变量的生命周期开始时被调用
构造函数不能被显示调用
可以重载
对于析构函数而言:

名称为~类名()
没有返回值
会在变量的生命周期结束时调用
可以显式调用(一般不这样做)
不能重载
关于自动调用时机的总结:

全局变量:构造函数在main之前调用,析构函数在main之后调用
局部变量:构造函数在进去函数开始时调用,析构函数在return之前调用
静态局部变量:构造函数在第一次进入函数时调用,析构函数在main之后调用
堆中的变量:构造和析构的调用时机由程序员自己控制,与new和delete什么时候被调用有关
默认构造:当需要构造函数(如有成员是对象,或者继承关系),而类中有没有实现构造函数。编译器会自动实现一个默认构造。
默认析构:同理,有需要时,编译器会偷偷实现一个默认析构,用于调用基类及成员的析构。

显式调用析构函数
显式调用的时候,析构函数相当于的一个普通的成员函数
编译器隐式调用析构函数,如分配了堆内存,显式调用析构的话引起重复释放堆内存的异常
把一个对象看作占用了部分栈内存,占用了部分堆内存(如果申请了的话),这样便于理解这个问题。系统隐式调用析构函数的时候,会加入释放栈内存的动作(而堆内存则由用户手工的释放)。用户显式调用析构函数的时候,只是单纯执行析构函数内的语句,不会释放栈内存,摧毁对象。
拷贝构造函数
拷贝构造函数是一种特殊的构造函数,它在创建对象时,是使用同一类中之前创建的对象来初始化新创建的对象。拷贝构造函数通常用于:

通过使用另一个同类型的对象来初始化新创建的对象。
复制对象把它作为参数传递给函数。
复制对象,并从函数返回这个对象。
如果在类中没有定义拷贝构造函数,编译器会自行定义一个。如果类带有指针变量,并有动态内存分配,则它必须有一个拷贝构造函数。拷贝构造函数的最常见形式如下:

classname(const classname &obj)
{
//构造函数的主体
}
xxxxxxxxxx4 1classname(const classname &obj)2{3 //构造函数的主体4}

在此,obj是一个对象引用,该对象是用于初始化另一个对象的。

#include

using namespace std;

class CLine
{
public:
int getLength(void);
CLine(int len); // 简单的构造函数
CLine(const CLine &obj); // 拷贝构造函数
~CLine(); // 析构函数

private:
int* ptr;
};

// 成员函数定义,包括构造函数
CLine::CLine(int len)
{
cout << “调用构造函数” << endl;
// 为指针分配内存
ptr = new int;
*ptr = len;
}

CLine::CLine(const CLine &obj)
{
cout << “调用拷贝构造函数并为指针 ptr 分配内存” << endl;
ptr = new int;
*ptr = *obj.ptr; // 拷贝值
}

CLine::~CLine(void)
{
cout << “释放内存” << endl;
delete ptr;
}
int CLine::getLength(void)
{
return *ptr;
}

void display(CLine obj)
{
cout << "line 大小 : " << obj.getLength() << endl;
}

// 程序的主函数
int main(int argc, char* argv[])
{
CLine line(10);

display(line);return 0;

}
xxxxxxxxxx56 1#include 2​3using namespace std;4​5class CLine6{7public:8 int getLength(void);9 CLine(int len); // 简单的构造函数10 CLine(const CLine &obj); // 拷贝构造函数11 ~CLine(); // 析构函数12​13private:14 int* ptr;15};16​17// 成员函数定义,包括构造函数18CLine::CLine(int len)19{20 cout << “调用构造函数” << endl;21 // 为指针分配内存22 ptr = new int;23 *ptr = len;24}25​26CLine::CLine(const CLine &obj)27{28 cout << “调用拷贝构造函数并为指针 ptr 分配内存” << endl;29 ptr = new int;30 *ptr = *obj.ptr; // 拷贝值31}32​33CLine::~CLine(void)34{35 cout << “释放内存” << endl;36 delete ptr;37}38int CLine::getLength(void)39{40 return ptr;41}42​43void display(CLine obj)44{45 cout << "line 大小 : " << obj.getLength() << endl;46}47​48// 程序的主函数49int main(int argc, char argv[])50{51 CLine line(10);52​53 display(line);54​55 return 0;56}

下面的实例对上面的实例稍作修改,通过使用已有的同类型的对象来初始化新创建的对象:

#include

using namespace std;

class CLine
{
public:
int getLength(void);
CLine(int len); // 简单的构造函数
CLine(const CLine &obj); // 拷贝构造函数
~CLine(); // 析构函数

private:
int *ptr;
};

// 成员函数定义,包括构造函数
CLine::CLine(int len)
{
cout << “调用构造函数” << endl;
// 为指针分配内存
ptr = new int;
*ptr = len;
}

CLine::CLine(const CLine &obj)
{
cout << “调用拷贝构造函数并为指针 ptr 分配内存” << endl;
ptr = new int;
*ptr = *obj.ptr; // 拷贝值
}

CLine::~CLine(void)
{
cout << “释放内存” << endl;
delete ptr;
}
int CLine::getLength(void)
{
return *ptr;
}

void display(CLine obj)
{
cout << "line 大小 : " << obj.getLength() << endl;
}

// 程序的主函数
int main(int argc, char* argv[])
{
CLine line1(10);

CLine line2 = line1; // 这里也调用了拷贝构造函数display(line1);
display(line2);return 0;

}
​x 1#include 2​3using namespace std;4​5class CLine6{7public:8 int getLength(void);9 CLine(int len); // 简单的构造函数10 CLine(const CLine &obj); // 拷贝构造函数11 ~CLine(); // 析构函数12​13private:14 int *ptr;15};16​17// 成员函数定义,包括构造函数18CLine::CLine(int len)19{20 cout << “调用构造函数” << endl;21 // 为指针分配内存22 ptr = new int;23 *ptr = len;24}25​26CLine::CLine(const CLine &obj)27{28 cout << “调用拷贝构造函数并为指针 ptr 分配内存” << endl;29 ptr = new int;30 *ptr = *obj.ptr; // 拷贝值31}32​33CLine::~CLine(void)34{35 cout << “释放内存” << endl;36 delete ptr;37}38int CLine::getLength(void)39{40 return ptr;41}42​43void display(CLine obj)44{45 cout << "line 大小 : " << obj.getLength() << endl;46}47​48// 程序的主函数49int main(int argc, char argv[])50{51 CLine line1(10);52​53 CLine line2 = line1; // 这里也调用了拷贝构造函数54​55 display(line1);56 display(line2);57​58 return 0;59}

拷贝构造函数是一种特殊的构造函数,具有单个形参,该形参(常用const修饰)是对该类类型的引用。当定义一个新对象并用一个同类型的对象对它进行初始化时,将显示使用拷贝构造函数。当该类型的对象传递给函数或从函数返回该类型的对象时,将隐式调用拷贝构造函数。
C++支持两种初始化形式:
拷贝初始化 int a = 5; 和直接初始化 int a(5); 对于其他类型没有什么区别,对于类类型直接初始化直接调用实参匹配的构造函数,拷贝初始化总是调用拷贝构造函数,也就是说:

CMyclass x(2);  //直接初始化,调用构造函数
CMyclass y = x;  //拷贝初始化,调用拷贝构造函数
1CMyclass x(2);  //直接初始化,调用构造函数2CMyclass y = x;  //拷贝初始化,调用拷贝构造函数

必须定义拷贝构造函数的情况:
只包含类类型成员或内置类型(但不是指针类型)成员的类,无须显式地定义拷贝构造函数也可以拷贝;有的类有一个数据成员是指针,或者是有成员表示在构造函数中分配的其他资源,这两种情况下都必须定义拷贝构造函数。
什么情况使用拷贝构造函数:
类的对象需要拷贝时,拷贝构造函数将会被调用。以下情况都会调用拷贝构造函数:

一个对象以值传递的方式传入函数体
一个对象以值传递的方式从函数返回
一个对象需要通过另外一个对象进行初始化。
推荐群:C++大学技术协会:145655849

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/504063.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

c++ 读取访问权限冲突_Linux系统利用可执行文件的Capabilities实现权限提升

一、操作目的和应用场景Capabilities机制是在Linux内核2.2之后引入的&#xff0c;原理很简单&#xff0c;就是将之前与超级用户root(UID0)关联的特权细分为不同的功能组&#xff0c;Capabilites作为线程(Linux并不真正区分进程和线程)的属性存在&#xff0c;每个功能组都可以独…

Python 数据分析 Matplotlib篇 时间序列数据绘制折线图(第4讲)

Python 数据分析 Matplotlib篇 时间序列数据绘制折线图(第4讲)         🍹博主 侯小啾 感谢您的支持与信赖。☀️ 🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹…

家装强电弱电布线图_家装水电施工标准(图文版),装修小白一眼也能看懂。...

如果把家比喻成一个人&#xff0c;房子是骨骼&#xff0c;那么水电路则相当于人体的血管和动脉&#xff0c;正因为他们的存在&#xff0c;才赋予家鲜活的生命。由此&#xff0c;水电施工自然也成为家装工程的重中之重。水电走线原则※ 水电弹线放样施工&#xff0c;使用切割机开…

0基础必看:如何轻松成为C语言高手

诞生于上世纪70年代的C语言是一门古老的语言了, 但作为一门底层语言,时至今日它仍然非常强大。学习C语言能够为学习其他更复杂的语言打下良好的基础&#xff0c;因为你在C语言中学习到的知识对几乎所有的编程语言都适用。下面就来看看如何开始用C语言编程吧。   工具   Mic…

python列表元素之和_python实现计算列表元素之和

目标&#xff1a;定义一个数字列表&#xff0c;并计算列表元素之和。 例如&#xff1a; 输入 : [12, 15, 3, 10] 输出 : 40 方法一&#xff1a;total 0 list1 [11, 5, 17, 18, 23] for ele in range(0, len(list1)): total total list1[ele] print("列表元素之和为: &…

双水泵轮换工作原理图_一用一备式冷凝水泵应急电源的设计与实现

为保障山西通州集团兴益化工有限公司10万吨甲醇工程一用一备式冷凝水泵的安全运行&#xff0c;专门设计动力负载应急电源。作者阐述了动力负载应急电源基本原理及其控制系统设计&#xff0c;经现场调试运行&#xff0c;动力负载应急电源很好满足生产现场要求。山西通州集团兴益…

基础学习——C语言递归解决分鱼问题

如有小伙伴想学习C语言基础&#xff0c;可以进群731871503进行交流学习&#xff0c;提升编程&#xff0c;共同进步 问题描述 A、B、C、D、E这5个人合伙夜间捕鱼&#xff0c;凌晨时都已经疲惫不堪&#xff0c;于是各自在河边的树丛中找地方睡着了。第二天日上三竿时&#xff0…

python定位元素在列表中的位置_python定位列表元素

Python 列表&#xff08;list&#xff09;提供了 index() 和 count() 方法&#xff0c;它们都可以用来查找元素。 index() 方法 index() 方法用来查找某个元素在列表中出现的位置&#xff08;也就是索引&#xff09;&#xff0c;如果该元素不存在&#xff0c;则会导致 ValueErr…

Java学习4大阶段完成入门,小白必读!

Java 的学习过程分为4个阶段&#xff1a; 理论阶段 开发阶段 进阶阶段 实战阶段 理论阶段 在具体谈论Java知识点之前&#xff0c;我想先跟同学们聊聊Java 语言自身的一些特点、生态系统以及适用的场景&#xff0c;这有助于我们更好的学习语言本身。 首先&#xff0c;我们…

memkind版本查看_不同价位值得买轻薄本推荐~2020国庆篇

说起轻薄本&#xff0c;你理想中的一台优秀机型是什么样的&#xff1f;轻薄便携、质感上乘、高颜值、逼格、手感佳、续航持久、屏幕素质高、独立小键盘、性能激进……和游戏本的鲜明对比&#xff0c;注定了是两种不同的“菜”。2020年&#xff0c;随着AMD的崛起&#xff0c;部分…

main方法 如何去掉http debug日志_在MyBatis中如何使用collection标签实现嵌套查询?...

# 需求升级在上篇博客《一对多的关系&#xff0c;在MyBatis中如何映射&#xff1f;》中&#xff0c;我们实现了需求&#xff1a;根据用户id查询用户信息的同时获取用户拥有的角色。因为角色可以拥有多个权限&#xff0c;所以本篇博客我们升级需求为&#xff1a;根据用户id查询用…

movielens推荐系统_案例|推荐系统的评估指标

推荐系统能够为用户提供个性化体验&#xff0c;现在基本上各大电商平台、资讯平台都会用推荐系统为自家评价下的用户提供千人千面的服务。平均精度均值&#xff08;Mean Average Precision&#xff0c;MAP&#xff09;便是评估推荐系统性能的度量标准之一。但是&#xff0c;使用…

mysql群集配置_CentOS7 - 建立一个MySQL集群

Standing up a MySQL cluster此配方将指导您完成设置MySQL群集的过程。 通过跨多个系统划分数据并维护副本以避免单点故障&#xff0c;群集数据库可以应对可伸缩性和高可用性的挑战。集群的成员称为节点。 MySQL集群中有三种节点类型&#xff1a;数据节点&#xff0c;API节点和…

叮!您收到一份超值Java基础入门资料!

Java语言有什么特点&#xff1f;如何最大效率的学习&#xff1f;深浅拷贝到底有何区别&#xff1f;阿里巴巴高级开发工程师为大家带来Java系统解读&#xff0c;带你掌握Java技术要领&#xff0c;突破重点难点&#xff0c;入门面向对象编程&#xff0c;以详细示例带领大家Java基…

python适用的操作系统是_操作系统先来先服务python

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 #codingutf-8 import __main__ import string def fcfs ( come_time , run_b_t , run_e_t , run_t , order ): # 先来先服务 time_tempcome_time [ 0 ] for i in range ( n ): run_b_t [ i …

jop怎么读音英语怎么说_“春晚”英语怎么说?

大家都说近年来的春节年味越来越淡&#xff0c;每年陪老人一起看春晚、上网吐槽春晚&#xff0c;应该算是最有年味的一件事了吧&#xff01;你期待今年的春晚吗&#xff1f;在春晚即将开播之际&#xff0c;先和我一起了解一些有关“春晚”的英语知识吧&#xff01;01、“春晚”…

2019 年软件开发人员必学的编程语言 Top 3

这篇文章将探讨编程语言世界的现在和未来&#xff0c;这些语言让新一代软件开发者成为这个数字世界的关键参与者&#xff0c;他们让这个世界变得更健壮、连接更加紧密和更有意义。开发者要想在 2019 年脱颖而出&#xff0c;这三门语言一定要关注。 作为软件开发者&#xff0c;…

python产生随机数random.random_Python内置random模块生成随机数的方法

本文我们详细地介绍下两个模块关于生成随机序列的其他使用方法。 随机数参与的应用场景大家一定不会陌生&#xff0c;比如密码加盐时会在原密码上关联一串随机数&#xff0c;蒙特卡洛算法会通过随机数采样等等。Python内置的random模块提供了生成随机数的方法&#xff0c;使用这…

数据仓库—stg层_数据仓库之Hive快速入门 - 离线实时数仓架构

数据仓库VS数据库数据仓库的定义:数据仓库是将多个数据源的数据经过ETL(Extract(抽取)、Transform(转换)、Load(加载))理之后&#xff0c;按照一定的主题集成起来提供决策支持和联机分析应用的结构化数据环境数据仓库VS数据库&#xff1a;数据库是面向事务的设计&#xff0c;数…

小数据量计算最大lyapunov代码_Software | 计算Lyapunov指数的GUI工具箱及函数包汇总...

二十年前读书时用过的Lyapunov Exponents Toolbox&#xff0c;推荐给做非线性动力学入门的同学们。那个时候不会编写程序&#xff0c;做分支图、算连续或者离散系统的Lyapunov指数&#xff0c;极其困难&#xff0c;还好有这个工具箱&#xff0c;慢慢看源程序学会写一点改进的程…