C++面向对象程序设计 - 构造函数

news2024/12/24 21:10:27

        C++提供了构造函数来处理对象的初始化,构造函数是一种特殊的成员函数,与其他成员函数不同,它不需要用户来调用,而是在建立对象时自动执行。构造函数名称必须与类同名,而不能由用户任意命名,以便编译系统能识别它把它作为构造函数处理。它不具体任何类型,也不返回任何值。构造函数的功能由用户定义,可根据初始化的要求设计函数体和函数参数。而且如果用户未定义构造函数,C++系统会自动生成一个构造函数,只是这个构造函数体是空的。

        

一、默认构造函数

        用户未定义构造函数系统会自动生成一个构造函数,这个构造函数的函数体是空的,也没有参数,不执行初始化操作。代码如下:

#include <iostream>
#include <string>
using namespace std;

class Student{
	private:
		int age;
		string name;
		string sex;
	public:
		void display(){
			cout <<"name:" <<name <<", age:" <<age <<", sex:" <<sex <<endl;
		}
};

int main(){
	Student s;
	s.display();
	return 0;
}

执行效果如下:

二、自定义构造函数

        构造函数没有返回值,也不需要在定义构造函数时声明类型。构造函数是在建立对象时由系统自动执行的,而且只执行一次。这里创建一个无参构造函数,代码如下:

#include <iostream>
#include <string>
using namespace std;

class Student{
	private:
		int age;
		string name;
		string sex;
	public:	
		Student(){
			age = 0;
			name = "test";
			sex = "male";
		}
		void display(){
			cout <<"name:" <<name <<", age:" <<age <<", sex:" <<sex <<endl;
		}
};

int main(){
	Student s;
	s.display();
	return 0;
}

        此时参数已在构造函数中初始化,执行效果如下:

三、构造函数的重载

        在一个类中可以定义多个构造函数,以便对类对象提供不同的初始化的方法供用户选择。这些构造函数名称相同,而参数的个数或参数类型不同,这称为构造函数的重载。代码如下:

#include <iostream>
#include <string>
using namespace std;

class Student{
	private:
		int age;
		string name;
		string sex;
	public:	
		// 不带参数构造函数
		Student(){
			age = 0;
			name = "test";
			sex = "male";
		}
		// 带参的构造函数
		Student(int a, string n, string s){
			age = a;
			name = n;
			sex = s;
		}
		void display(){
			cout <<"name:" <<name <<", age:" <<age <<", sex:" <<sex <<endl;
		}
};

int main(){
	Student s, s2(10, "jack", "male");
	s.display();
	s2.display();
	return 0;
}

        运行结果如下:

四、参数初始化表

        C++提供了一种特殊的初始化数据成员方法(参数初始化表来实现对数据成员的初始化),这种方法不在函数体内实现数据的初始化,而在函数首部实现。代码如下:

#include <iostream>
#include <string>
using namespace std;

class Student{
	private:
		int age;
		string name;
		string sex;
	public:	
		// 不带参数构造函数
		Student(){
			age = 0;
			name = "test";
			sex = "male";
		}
		// 带参的构造函数,并且使用参数初始化表对数据成员的初始化
		Student(int a, string n, string s) : age(a), name(n), sex(s){}
		
		void display(){
			cout <<"name:" <<name <<", age:" <<age <<", sex:" <<sex <<endl;
		}
};

int main(){
	Student s, s2(10, "jack", "male");
	s.display();
	s2.display();
	return 0;
}

        这种写法方便、简练,尤其当需要初始化的数据成员较多时更显其优势。运行结果如下:

五、类体外定义构造函数

        除在类内定义构造函数,也可以在类外定义构造函数,要类名加上两个冒号“::”域限定符来实现。代码如下:

#include <iostream>
#include <string>
using namespace std;

class Student{
	private:
		int age;
		string name;
		string sex;
	public:	
		// 声明不带参数构造函数
		Student();
		// 带参的构造函数,并且使用参数初始化表对数据成员的初始化
		Student(int, string, string);
		
		void display(){
			cout <<"name:" <<name <<", age:" <<age <<", sex:" <<sex <<endl;
		}
};

int main(){
	Student s, s2(10, "jack", "male");
	s.display();
	s2.display();
	return 0;
}

// 类体外定义无参构造函数
Student::Student(){
		age = 0;
		name = "test";
		sex = "male";
}
// 在类体外定义带参构造函数
Student::Student(int a, string n, string s) : age(a), name(n), sex(s){}

        运行结果如下:

六、构造函数添加默认参数

        在成员函数中可以使用有默认的参数,构造函数也可以使用包含默认参数的构造函数。代码如下:

Student::Student(int a = 15, string n = "Tom", string s = "female") : age(a), name(n), sex(s){}

        如果构造函数全部参数都指定了默认值,则在定义对象时可以给一个或几个实参,也可以不给出实参;但应该执行哪一个构造函数,会出现歧义,系统无法识别编译时会报错([Error] no matching function for call to 'Student::Student()')。这块操作对程序员来说,开发难度会加大,所以不建议使用。

七、析构函数

        析构函数是C++中的一个特殊的成员函数,它的作用与构造函数相反,它的名字是类名前面加一个“~”符号。在以C++中“~”是位取反运算符,所它是与构造函数作用相反的函数。当对象的生命期结束时,会自动执行析构函数。在以下几种情况会执行析构函数:

  1. 在一个函数中定义一个对象,当这个函数被调用结束时,对象应该释放,在对象释放前自动执行析构函数。
  2. static局部对象在函数调用结束时对象并不释放,因此也不调用析构函数,只在main函数结束或调用exit函数结束程序时,才调用static局部对象的析构函数。
  3. 定义了一个全局对象,则在程序的流程离开其作用域时,调用该全局对象的析构函数。
  4. 如果用new运算符动态地建立一个对象,当用delete运算符释放该对象时,先调用该对象的析构函数。

以上几种方法演示代码如下:

#include <iostream>
#include <string>
using namespace std;

class Student{
	private:
		int age;
		string name;
		string sex;
	public:	
		// 声明不带参数构造函数
		Student();
		// 带参的构造函数,并且使用参数初始化表对数据成员的初始化
		Student(int, string, string);
		// 定义析构函数
		~Student(){
			cout <<"Destructor called:" <<name <<endl;
		}
		
		void display(){
			cout <<"name:" <<name <<", age:" <<age <<", sex:" <<sex <<endl;
		}
};

// 对象在函数内执行
void show_student(){
	Student t1(15, "Lily", "femail");
	t1.display();
}

int main(){
    // 在函数中定义一个对象执行后,执行析构函数
	show_student();
    // 当对象定义全局(如main函数结束),执行析构函数
	Student s;
	s.display();
	// 当static局部对象在main函数结束后,执行析构函数
	static Student s2(10, "jack", "male");
	s2.display();
	// 当用new运算符动态地建立一个对象
	Student *p = new Student(12, "John", "male");
	p->display();
	return 0;
}

// 类体外定义无参构造函数
Student::Student(){
	age = 0;
	name = "test";
	sex = "male";
}
// 在类体外定义带参构造函数
Student::Student(int a = 15, string n = "Tom", string s = "female") : age(a), name(n), sex(s){}

        执行后支行结果:

        可以看出,首先show_student()函数执行完后,其内部t1对象已结束并执行析构函数;然后定义全局对象和static局部对象,在main函数执行结束后,也相继执行析构函数;但是始终未见用new运算符动态建立的对象执行析构函数,这是因为没用delete运算符释放对象,现在咱们加再运行看下结果,代码如下:

Student *p = new Student(12, "John", "male");
p->display();
delete p;

        运行结果如下:

        此时用new建立的对象也执行了析构函数,从这也可以看出,John在test、jack之前执行析构函数,恰好说明了定义在全局对象和static局部对象是在main函数执行结束后,执行的析构函数。

c++构造函数与其他开发语言相比,不仅有很多相似之处,也有独特之处。相似之处有其命名中与类同名且无返回类型,自动调用与初始化,可重载性等外,还可以在类体外定义构造函数,参数初始化表,析构函数等。

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

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

相关文章

macbook(m1) ubuntu下载,复制粘贴和国内镜像源配置

ubuntu下载使用 官网下载Ubuntu 22.04.4 LTS (Jammy Jellyfish) Daily Build 打开后根据电脑的架构选择安装包&#xff0c;想要下载其他版本也可在官网中自行搜索。 我安装时舍友说他安装的是22.04这个版本&#xff0c;我也就跟着他安装了 注意&#xff1a;下载的版本最好有…

TCP、UDP协议

TCP与UDP协议的区别 TCP&#xff08;Transmission Control Protocol&#xff09;和UDP&#xff08;User Datagram Protocol&#xff09;是两种常用的传输层协议&#xff0c;它们之间有以下几点区别&#xff1a; 1. 连接性&#xff1a; - TCP是面向连接的协议&#xff0c;通…

PostgreSQL的学习心得和知识总结(一百三十五)|深入理解PostgreSQL数据库之查找 PostgreSQL C 代码中的内存泄漏

目录结构 注&#xff1a;提前言明 本文借鉴了以下博主、书籍或网站的内容&#xff0c;其列表如下&#xff1a; 1、参考书籍&#xff1a;《PostgreSQL数据库内核分析》 2、参考书籍&#xff1a;《数据库事务处理的艺术&#xff1a;事务管理与并发控制》 3、PostgreSQL数据库仓库…

Flutter混淆方案对应用性能的影响分析与优化

在移动应用开发中&#xff0c;保护应用代码安全至关重要。Flutter 提供了简单易用的混淆工具&#xff0c;帮助开发者在构建 release 版本应用时有效保护代码。本文将介绍如何在 Flutter 应用中使用混淆&#xff0c;并提供了相关的操作步骤和注意事项。 &#x1f4dd; 摘要 本…

练习 17 Web [极客大挑战 2019]PHP

常见的网站源码备份文件名和后缀&#xff0c;反序列化攻击 unserialize()&#xff1a;wakeup绕过&#xff0c;private类以及属性序列化后的%00修改 开靶机 提到”备份“ 那看看有没有backup.php啥的 如果网站存在备份文件&#xff0c;常见的备份文件后缀名有&#xff1a;“.gi…

解读命令:icacls “E:\ShareAll“ /grant “Everyone:(OI)(CI)(F)“

命令 icacls "E:\ShareAll" /grant "Everyone:(OI)(CI)(F)" 是在Windows操作系统中用来修改文件或目录权限的命令行操作。该命令执行以下操作&#xff1a; 路径&#xff1a;"E:\ShareAll" 指定了要更改权限的目录位置&#xff0c;即对E盘下的“S…

UDP实现聊天直播间 chatroom

1.memcmp() 函数 int memcmp(const void *s1, const void *s2, size_t n); memcmp() 函数用于比较两个内存区域前 n 个字节的内容。 它接受三个参数&#xff1a; •const void *s1&#xff1a;指向第一个内存区域的指针。 •const void *s2&#xff1a;指向第二个内存区域的…

Java SpringBoot中优雅地判断一个对象是否为空

在Java中&#xff0c;可以使用以下方法优雅地判断一个对象是否为空&#xff1a; 使用Objects.isNull()方法判断对象是否为空&#xff1a; import java.util.Objects;if (Objects.isNull(obj)) {// obj为空的处理逻辑 }使用Optional类优雅地处理可能为空的对象&#xff1a; impo…

使用Excel连接Azure DevOps自动退出的问题

Azure DevOps Server (原名TFS)是微软公司的软件开发管理平台&#xff0c;也是著名的软件开发过程管理工具&#xff1b;系统中记录了软件开发过程中的需求、问题、缺陷和迭代计划等各种软件开发工作项数据。 对于工作项数据的批量操作(例如新增和编辑)&#xff0c;Excel是一个非…

关于不同AR(增强现实)SDK(软件开发工具包)的汇总和特性描述

以下是每个AR SDK的核心内容概述: ARCore 开发者:Google支持平台:Android(部分设备不支持)功能:运动追踪、平面追踪、点云图、云锚点、光照估计、环境探针、人脸追踪、2D图片追踪、人物遮挡、射线测试。官网链接:ARCoreARKit 开发者:Apple支持平台:iOS(iPhone和iPad)…

【VSCode+Keil5+STM32CubeMX】开发环境配置

一、软件下载 二、软件安装 三、配置环境 四、验证开发环境 五、Keil与VS Code的同步 从0到1搭建VS Code Keil5 STM32CubeMX开发环境 优点 支持标准库HAL库LL库代码编辑更“现代化”&#xff1a;代码提示、函数跳转、更高自由度的定制主题等优点多端同步&#xff0c;VS Code和…

【Linux】在生产环境中,Linux系统排查常用命令

问题排查 文章目录 问题排查top命令CPU&#xff1a;vmstatprocscpu内存&#xff1a;free硬盘&#xff1a;df硬盘IO&#xff1a;iostat网络IO&#xff1a;ifstat 生产环境服务器变慢&#xff0c;诊断思路和性能评估 top命令 查看整机系统新能 使用top命令的话&#xff0c;重点…

大数据分析与内存计算——Spark安装以及Hadoop操作——注意事项

一、Spark安装 1.相关链接 https://dblab.xmu.edu.cn/blog/4322/ 2.安装Spark&#xff08;Local模式&#xff09; 按照文章中的步骤安装即可 遇到问题&#xff1a;xshell以及xftp不能使用 解决办法&#xff1a; 在linux使用镜像网站进行下载&#xff1a;wget https://mi…

视频汇聚/安防监控/视频存储EasyCVR平台EasyPlayer播放器更新:新增【性能面板】

视频汇聚/安防监控/视频存储平台EasyCVR基于云边端架构&#xff0c;可以在复杂的网络环境中快速、灵活部署&#xff0c;平台视频能力丰富&#xff0c;可以提供实时远程视频监控、视频录像、录像回放与存储、告警、语音对讲、云台控制、平台级联、磁盘阵列存储、视频集中存储、云…

ClickHouse集群搭建教程

文章目录 前言一、相关介绍1. 端口介绍 二、部署规划1. 准备centos2. 配置集群免密登录3. 部署规划 三、ckman依赖部署1. prometheus搭建1.1 下载并解压1.2 配置启停服务1.3 promethues配置(可选&#xff0c;不影响ckman核心功能)1.4 prometheus启停命令1.4.1 启动prometheus1.…

安全架构设计理论与实践相关知识总结

一、安全架构概述 常见信息威胁介绍&#xff1a; 1. 信息泄露&#xff1a;信息被泄露或透露给某个非授权实体 2. 破坏信息完整性&#xff1a;数据被非授权地进行增删改查货破坏而受到损失 3. 拒绝服务&#xff1a;对信息会其他资源的合法访问被无条件的组织 4. 非法使用&#x…

vue 加 websocket 聊天

<template><div style="height: 100%; width: 100%; background-color: #fff"><div class="wrap"><!-- 头部 --><div class="titleBox"><imgsrc="@/assets/image/avatar.png"style="argin: 10p…

《数据结构学习笔记---第九篇》---循环队列的实现

文章目录 1.循环队列的定义 2.循环队列的判空判满 3.创建队列并初始化 4.入队和出队 5. 返回队尾队首元素 6.释放循环队列 1.循环队列的定义 定义&#xff1a;存储队列元素的表从逻辑上被视为一个环。 我们此次实现的循环队列&#xff0c;采用顺序表 typedef struct {int…

Scikit-Learn K均值聚类

Scikit-Learn K均值聚类 1、K均值聚类1.1、K均值聚类及原理1.2、K均值聚类的优缺点 2、Scikit-Learn K均值聚类2.1、Scikit-Learn K均值聚类API2.2、K均值聚类案例 1、K均值聚类 K-均值&#xff08;K-Means&#xff09;是一种聚类算法&#xff0c;属于无监督学习。K-Means在机器…

Linux学习笔记————C 语言版 LED 灯实验

这里写目录标题 一、实验程序编写二、 汇编部分实验程序编写三、C 语言部分实验程序编写四、编译下载验证 汇编 LED 灯实验中&#xff0c;我们讲解了如何使用汇编来编写 LED 灯驱动&#xff0c;实际工作中是很少用到汇编去写嵌入式驱动的&#xff0c;毕竟汇编太难&#xff0c;而…