C++-构造与解析

构造函数

构造函数是与同类名的特殊成员函数,主要用来初始化对象的数据成员。

构造函数的特点:

  • 与类同名
  • 没有返回类型
  • 可以被重载
  • 由系统自动调用,不允许在程序中显示调用。
#include <iostream>
using namespace std;class student{
private:string m_name;int m_age;int m_num;public:student(const string &name, int age, int num) {m_name = name;m_age = age;m_num = num;}void Cout() {cout << "my name is " << m_name << "," << "my age is " << m_age << endl;}};int main(int argc, const char *argv[])
{student s("xiaoming", 18, 1234);s.Cout();return 0;
}

缺省构造函数

缺省构造函数也称无参构造函数,但其未必真的没有任何参数,为一个有参构造函数的每个参数都提供一个缺省值,同样可以达到无参构造函数的效果。

注意:

  • 如果一个类没有定义任何构造函数,那么编译器会为其提供一个缺省构造函数
  • 对基本类型的成员变量,不做初始化
  • 对类类型的成员变量(成员子对象),将自动调用相应类的缺省构造函数来初始化。
#include <iostream>
using namespace std;class A{public:A(void) {cout << "这是A的构造函数" << endl;m_t = 0;}
public:int m_t;
};class B{
public:int m_j;//基本类型成员变量A m_a;//类类型成员变量(成员子对象)};
int main(int argc, const char *argv[])
{B b;//调用成员对象m_a的无参构造函数 调用B的缺省构造函数cout << b.m_j << endl;cout << b.m_a.m_t << endl;return 0;
}

构造函数的重载

#include <iostream>
using namespace std;class Desk{
private:int length, weight, hight, wide;
public:Desk(int l, int w, int h, int ww);void put() {cout << length << weight << hight << wide << endl;}Desk() {cout << "Desk(void)" << endl;length = 0;weight = 0;hight = 0;wide = 0;}
};Desk::Desk(int l, int w, int h, int ww) {cout << "construct" << endl;length = l;weight = w;hight = h;wide = ww;
}
int main(int argc, const char *argv[])
{Desk s(1,2,3,4);s.put();Desk();return 0;
}

类型转换构造函数

将其他类型转换为当前类类型需要借助转换构造函数,转换构造函数只有一个参数。

#include <iostream>
#include <cstring>using namespace std;class test {private:int m_i;string m_c;public:test(void) {cout << "test(void)" <<endl;m_i = 0;}explicit test(int n) {cout << "test(int)" << endl;//类型转换构造函数m_i = n;}explicit test(const char *str) {cout << "test(char *)" << endl;m_i = strlen(str);m_c = str;cout << m_c << endl;}void printf() {cout << m_i << endl;}};
int main(int argc, const char *argv[])
{test a1;a1.printf();test a = test(2);//编译器会找参数类型为int的构造参数a.printf();	test b = test("abc");//编译器会找参数类型为char *的构造参数b.printf();return 0;
}

explicit关键字,就是告诉编译器需要类型转换时,强制要求写成如下形式:

test a = test(2);
test a = 2;//会报错

拷贝构造函数

用一个已定义的对象构造同类型的副本对象,将调用该类的拷贝构造构造函数

class A{A(const A &that){//拷贝构造函数,注意参数必须是常引用...}
};A a;A b(a);//调用拷贝构造A c = a;//调用拷贝构造
#include <iostream>
using namespace std;class A{public:int m_t;A(int date = 0) {cout << "A(int)" << endl;m_t = date;}A(const A& that) {//拷贝构造函数cout << "A(const A&)" << endl;m_t = that.m_t;}
};
int main(int argc, const char *argv[])
{A a;A b(a);//编译器会调用拷贝构造函数A c = a;//调用拷贝构造函数return 0;
}
  • 如果一个类没有显式定义拷贝构造函数,那么编译器会为其提供一个缺省拷贝构造函数
  • 对基本类型成员变量,按字节复制
  • 对类类型成员(成员子对象),调用相应类型的拷贝构造函数
class User {string m_name;//调用string类的拷贝构造函数int m_age;//按字节复制
};
#include <iostream>
using namespace std;class A{public:int m_t;A(int date = 0) {cout << "A(int)" << endl;m_t = date;}A(const A& that) {//拷贝构造函数cout << "A(const A&)" << endl;m_t = that.m_t;}
};class B{
public:A m_a;
};int main(int argc, const char *argv[])
{
#if 0A a;A b(a);//编译器会调用拷贝构造函数A c = a;//调用拷贝构造函数B d;
#endifB b;b.m_a.m_t = 98;B b1;b1 = b;cout << b1.m_a.m_t << endl;//调用B的缺拷贝构造函数,由于有成员对象m_t,所以会调用A的拷贝构造函数return 0;
}

初始化列表

构造函数的初始化列表

构造函数对数据成员进行初始化还可以通过成员初始化列表的方式完成。语法格式为:

构造函数名(参数表):成员1(初始值参数),成员2(初始值参数){

}

例如:

#include <iostream>
using namespace std;class Desk{
private:int length, weight, hight, wide;
public:Desk(int l, int w, int h, int ww);void put() {cout << length << weight << hight << wide << endl;}Desk() {cout << "Desk(void)" << endl;}
};Desk::Desk(int l, int w, int h, int ww) :length(l), weight(w), hight(h), wide(ww){cout << "construct" << endl;length = l;weight = w;hight = h;wide = ww;
}
int main(int argc, const char *argv[])
{Desk s(1,2,3,4);s.put();Desk s2;return 0;
}

需要显式初始化列表的场景

一般而言,使用初始化列表和在构造函数体对成员变量进行赋初值,两者区别不大,可以人员一种,但是下面几种场景必须使用初始化列表:

  • 如果有类类型的成员变量(成员子对象),而该类有没有无参构造函数,则必须要通过初始化列表显式指明其初始化方式。
#include <iostream>
using namespace std;class A{
private:int date_t;
public:A(int date) {date_t = date;cout << "A(int)" << endl;}
};class B {
private:int m_t;
public:B(void) :m_t(123){cout << "B(void)" << endl;cout << m_t << endl;}
};
int main(int argc, const char *argv[])
{B b;//一定会去构造成员对象m_t,未指定如何构造,系统去调用m_t的无参构造函数return 0;
}
  • 被const修饰的成员变量(常成员变量)必须要在初始化列表中初始化参数
  • 引用型成员变量必须要在初始化列表中初始化
#include <iostream>
using namespace std;int num = 100;
class A{
public:int & m_t;const int m_c;
/** error此种写法错误,无法const类型和引用类型无法这样初始化A(void) {m_t = num;m_c = 100;}
*/A(void):m_t(num),m_c(num) {cout << m_t << " " << m_c << endl;}
};int main(int argc, const char *argv[])
{A a;return 0;
}

初始化顺序

类中成员变量按声明顺序依次被初始化,而与初始化中的顺序无关。

#include <iostream>
using namespace std;class A{
public:A(int a) {cout << "A(construct)" << endl;}
};class B{
public:B(int b) {cout << "B(construct)" << endl;}
};class C{
private:A m_a;B m_b;
public:C(int a, int b): m_b(b), m_a(a) {}
};int main(int argc, const char *argv[])
{C c(2,3);return 0;
}

this指针

什么是this指针

#include <iostream>
using namespace std;class stu{
private:int age;string name;public:stu(int m_age, string m_name) {//编译完成之后就是stu(stu *this, int m_age, string m_name);age = m_age;name = m_name;}void cprintf() {cout << name << ":" << age << endl;}
};
int main(int argc, const char *argv[])
{stu zs(18,"zhangsan");//传递参数为(&zs,18,"zhangsan");stu ls(21,"lisi");//传递参数为(&ls, 21, "lisi");zs.cprintf();ls.cprintf();return 0;
}

this是一个用于标识对象自身的隐式指针,代表对象自身的地址。

在编译类成员函数时,C++编译器会自动将this指针添加到成员函数的参数表中。在用类的成员函数时,调用对象会把自己的地址通过this指针传递给成员函数。

this指针有什么用

需要显式使用this指针的常见场景:

  • 类中的成员变量和参数变量名字一样,可以通过this指针区分
  • 从成员函数中返回调用对象自身(返回自引用),支持链式调用
  • 在成员函数中销毁对象自身(对象自销毁)
#include <iostream>
using namespace std;class Count{private:int count;public:Count(int count = 0) {this->count = count;}Count &add(void) {++count;return *this;}void printf() {cout << count << endl;}void destroy() {cout << "this:" << this << endl;delete this;}
};int main(int argc, const char *argv[])
{Count cnt;cnt.printf();cnt.add().add().add();cnt.printf();Count *pnt = new Count;pnt->printf();pnt->add();pnt->printf();pnt->destroy();cout << pnt << endl;return 0;
}

常成员函数

在C++中,为了禁止成员函数修改成员数据的值,可以将它设置为常成员函数。设置方法就是在函数体之前加上const关键字。

class X{void func(参数1, 参数2, ...) const {}
};
#include <iostream>
using namespace std;class A {
private:int num,age;string name;
public:A(int num, const string &name, int age) {this->age = age;this->num = num;this->name = name;}void printf(void) const{cout << "i am " << name << "i am age is " << age << "num:" << num << endl;}};
int main(int argc, const char *argv[])
{A a(8499, "zhangsan", 21);a.printf();return 0;
}

常函数的使用注意事项:

  • 常对象只能调用常函数,非常对象既可以调用非常函数,也可以调用常函数
  • 函数名和形参表相同的成员函数,常版本和非常版本可以构成重载
    • 常对象只能选择常版本
    • 非常对象优先选择非常版本
  • 被mutable修饰的成员可以常函数中修改(了解)
#include <iostream>
using namespace std;class A{
private:int n,m;
public:A(int nn = 1, int mm = 2):n(nn),m(mm) {};void func(void) {cout << "this is 11" << endl;}void bar(void) const{cout << "this is 15"<< endl;}void func(void) const{cout << "this is 19" << endl;}
};
int main(int argc, const char *argv[])
{A a;a.func();a.bar();const A b;b.func();return 0;
}

析构函数

析构函数是与类同名的另一个特殊成员函数,作用与构造函数相反,用于对象生存期结束时,完成对象的清理工作。析构函数的名称是:~类名

class X{
public:X() {//构造函数}~X() {//析构函数}
};

析构函数的特点:

  • 无参无返回值
  • 不能重载
  • 只能由系统调用,不能显示调用
    • 栈对象,离开其作用域时析构函数自动调用
    • 堆对象,执行delete操作时析构函数自动调用
#include <iostream>
using namespace std;class Integer{
private:int *m;public:Integer(int i = 0) {m = new int(i);}~Integer(void) {cout << "析构函数" << endl;delete m;}void printf(void) {cout << *m << endl;}
};
int main(int argc, const char *argv[])
{if(1) {Integer a(100);a.printf();cout << "test1" << endl;Integer *pi = new Integer(200);pi->printf();delete pi;cout << "test2" << endl;}cout << "test3" << endl;return 0;
}

缺省析构函数

如果类没有显式定义析构函数,那么编译器会为其提供一个缺省析构函数,缺省析构的函数体为空,在析构函数体执行完毕后,类中的成员会被自动销毁。

  • 对基本类成员变量,什么也不做
  • 对类类成员变量(成员子对象),将会自动调用相应类的析构函数。
#include <iostream>
using namespace std;class A{
public:A(void) {cout << "A(void)" << endl;}~A(void) {cout << "~A(void)" << endl;}};class B{
public:B(void) {cout << "B(void)" << endl;}~B(void) {cout << "~B(void)" << endl;}A a;};int main(int argc, const char *argv[])
{B b;return 0;
}

对象的穿件和销毁的过程

对象创建

  • 分配内存
  • 构造成员对象
  • 调用构造函数

对象销毁

  • 调用析构函数
  • 析构成员对象
  • 释放内存

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

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

相关文章

用友NC word.docx 任意文件读取漏洞复现

0x01 产品简介 用友NC是一款企业级ERP软件。作为一种信息化管理工具,用友NC提供了一系列业务管理模块,包括财务会计、采购管理、销售管理、物料管理、生产计划和人力资源管理等,帮助企业实现数字化转型和高效管理。 0x02 漏洞概述 用友NC 系统word.docx等接口存在任意文件…

JavaScript 基础二part1.运算符:赋值、一元、比较、逻辑运算符

JavaScript 基础二 1.1 赋值运算符1.2 一元运算符自增运算符的用法&#xff1a;例题 1.3 比较运算符不同类型间的比较严格相等对 null 和 undefined 进行比较 1.4 逻辑运算符例题 1.5 运算符优先级 1.1 赋值运算符 赋值运算符&#xff1a;对变量进行赋值的运算符 已经学过的赋…

光速爱购--靠谱的SpringBoot项目

简介 这是一个靠谱的SpringBoot项目实战&#xff0c;名字叫光速爱购。从零开发项目&#xff0c;视频加文档&#xff0c;十天就能学会开发JavaWeb项目。 教程路线是&#xff1a;搭建环境> 安装软件> 创建项目> 添加依赖和配置> 通过表生成代码> 编写Java代码&g…

2023年12 月电子学会Python等级考试试卷(四级)答案解析

青少年软件编程(Python)等级考试试卷(四级) 分数:100 题数:38 一、单选题(共25题,共50分) 1. 下列有关分治算法思想的描述不正确的是?( ) A. 将问题分解成的子问题具有相同的模式。

C语言中的printf函数详解

介绍 在C语言中&#xff0c;printf函数是一个非常重要的输出函数&#xff0c;用于在屏幕上显示各种数据类型的值。它通过占位符来指定输出的格式&#xff0c;并可以根据需要进行格式化输出。 常用的占位符列表 以下是printf函数中常用的占位符列表&#xff1a; %a &#xf…

HarmonOS 通用组件(Checkbox)

本文中 我们来说 通用组件中的 Checkbox 我们先搭起一个基本的架子组件 Entry Component struct Index {build() {Row() {Column() {Row() {}}.width(100%)}.height(100%)} }我们可以在Row 行组件中加入代码 Checkbox({name: "age"}) Text("年龄")这样 就…

专为Mac用户设计的思维导图软件MindNode 2023 for Mac助您激发创意!

在现代快节奏的生活中&#xff0c;我们经常需要整理思绪、规划项目、记录灵感。而思维导图作为一种高效的思维工具&#xff0c;能够帮助我们更好地整理和展现思维。现在&#xff0c;我们介绍一款强大而直观的思维导图软件——MindNode 2023 for Mac&#xff0c;助您拓展思维边界…

计算机毕业设计 基于Javaweb的城乡居民基本医疗信息管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

log4cpp日志库使用

Log4cpp是一个开源的C类库&#xff0c;它提供了C程序中使用日志和跟踪调试的功能&#xff0c;它提供了应用程序运行上下文&#xff0c;方便跟踪调试&#xff1b;可扩展的、多种方式记录日志&#xff0c;包括命令行、文件、回卷文件、内存、syslog服务器、Win事件日志等&#xf…

【EAI 004】LLM+P:借助LLM和PDDL赋予机器人最优规划能力

论文标题&#xff1a;LLMP: Empowering Large Language Models with Optimal Planning Proficiency 论文作者&#xff1a;Bo Liu, Yuqian Jiang, Xiaohan Zhang, Qiang Liu, Shiqi Zhang, Joydeep Biswas, Peter Stone 作者单位&#xff1a;Department of Computer Science, Th…

Grouping Increases

您将得到一个大小为 n 的数组 a。您将执行以下过程来计算惩罚&#xff1a;将数组 a 拆分为两个子序列 s 和 t&#xff08;可能为空&#xff09;&#xff0c;使 a 的每个元素都在 s 或 t 中。 对于大小为 m 的数组 b&#xff0c;将数组 b 的惩罚 p(b) 定义为介于 1 和 m−1 之间…

安科瑞电力物联网系统在电力设备在线监测中的应用——安科瑞 顾烊宇

摘要&#xff1a;近年来&#xff0c;社会经济发展速度不断提升&#xff0c;对电力能源的需求大幅增加&#xff0c;为保障变电站等电力设备合理发挥功能&#xff0c;保障供电安全性和稳定性&#xff0c;应当加强对电力设备的监测和管理。而电力物联网技术是现代一种安全工器具的…

记一个React组件入参不当导致页面卡死的问题

一、问题描述 1.1 触发现象 点击按钮后页面卡死 1.2 最小 Demo CodeSandBox&#xff1a;https://codesandbox.io/p/sandbox/react-hook-component-stuck-755wcyinscode&#xff1a;https://inscode.csdn.net/ import ./App.css; import React, { useState, useEffect } f…

JVM中对象的创建

一.JVM运行流程 JVM向操作系统申请内存&#xff0c;初始化运行时数据区&#xff0c;接下来装载使用的类&#xff0c;执行类里面相应方法的时候为当前虚拟机栈压入一个栈帧&#xff0c;方法执行完成后栈帧出栈&#xff0c;进行垃圾回收。 二.JVM中对象的创建过程 符号引用&…

第03章_运算符与流程控制

第03章_运算符与流程控制 讲师&#xff1a;尚硅谷-宋红康&#xff08;江湖人称&#xff1a;康师傅&#xff09; 官网&#xff1a;http://www.atguigu.com 本章专题脉络 1. 运算符&#xff08;Operator&#xff09; 运算符是一种特殊的符号&#xff0c;用以表示数据的运算、赋…

CSS基础笔记-04cascade-specificity-inheritance

CSS基础笔记系列 《CSS基础笔记-01CSS概述》《CSS基础笔记-02动画》CSS基础笔记-03选择器 前言 Cascading Style Sheets&#xff0c;关键就在于这个cascading&#xff0c;对于这个术语理解&#xff0c;感觉对于我这种CSS新手有点儿不太friendly。本文记录下我对这个术语的理…

CoroutineScope Dispatchers.IO异步操作async返回函数,Kotlin

CoroutineScope Dispatchers.IO异步操作async返回函数&#xff0c;Kotlin import kotlinx.coroutines.*fun myFun(a: Int, b: Int, retFun: (sum: Int) -> Unit) {println("分支myFun开始... ${System.currentTimeMillis()}")val task CoroutineScope(Dispatcher…

互联网分布式应用之SpringCloud

SpringCloud Java 是第一大编程语言和开发平台。它有助于企业降低成本、缩短开发周期、推动创新以及改善应用服务。如今全球有数百万开发人员运行着超过 51 亿个 Java 虚拟机&#xff0c;Java 仍是企业和开发人员的首选开发平台。 课程内容的介绍 1. 微服务项目介绍 2. Eure…

修复 OpenCV 依赖错误的小工具:OpenCV Fixer

使用 Nvidia 官方 Docker 镜像折腾 Stable Video Diffusion 的时候&#xff0c;发现 OpenCV 社区有一个古怪的 issue 需要手动解决&#xff0c;所以顺手写了一个能够自动修复的小工具。 以及&#xff0c;聊聊如何快速的发布一个 Python 软件包。 写在前面 如果你在使用 Pyth…

kafka-zookeeper集群架构可视化监控,Kafka-Eagle安装部署

1、简介 在 kafka-zookeeper 集群架构下&#xff0c;zookeeper 管理 kafka 的元数据信息&#xff0c;如何监控这些信息&#xff0c;并且能够直观查看和管理 kafka 一些具体 主题、分区等参数信息&#xff0c;是非常便于开发的&#xff0c;因此 Kafka-Eagle 是一个为监控 kafka …