C++类和对象(1):构造函数和析构函数

一.类与对象的基本概念

1.结构体与类

C++提供了一种比结构体类型更安全有效的数据类型——。并且用class取代struct。

在C++中将类的成员分为两类:私有成员(用private说明)和公有成员(用public说明)。私有成员(包括数据成员和成员函数)只能被类内的成员函数访问,而不能被类外的对象访问;公有成员(包括数据成员和成员函数)既可被类内的成员函数访问,也可被类外的对象访问。但在C++中(即没有指定属于私有或公有时),类内的成员是私有的

代码解释如下:
 

#include<iostream>
#include<cmath>
using namespace std;
class Complex
{
	private:
		double real,imag;
	public:
	    void init(double r,double i)
		{
			real=r;
			imag=i;
		}
		double abs()
		{
			double t;
			t=real*real+imag*imag;
			return sqrt(t);
		} 		 
};
int main()
{
	Complex A;
	A.init(1.1,2.2);
	cout<<A.abs()<<endl;
	return 0;
}

在所示代码中,类外的对象A是无法对类内的私有成员进行直接访问。所以主函数中的代码语句
    A.init(1.1,2.2);
    cout<<A.abs()<<endl;

在编译时是错误的。

类类型的声明为:

class 类名
{

private:

          私有成员和成员函数

public:
           公有成员和成员函数

};

除了private和public之外,类中的成员还可以用另一个关键字protected来说明。被protected说明的数据成员和成员函数称为保护成员

2.成员函数

成员函数可以访问本类中的任何成员。

成员函数在类外定义的一般形式为:
返回值类型 类名::成员函数名(参数表)

{

函数体

}

注:

(1)在类的声明中,成员函数的原型的参数表中可以不说明参数的名字,而只说明它们的类型。如:

void setpoint(int,int);

但是,在类外定义成员函数时,不但要说明参数表中的参数类型,还必须要指出其参数名

(2)成员函数还可以直接定义在类的内部。如:

class Point
{
    public:
        void setpoint(int a,int b)         //成员函数setpoint直接定义在类的内部
        {
            x=a;
            y=b;
        }
        int getx()                         //成员函数getx直接定义在类的内部
        {
            return x;
        }
        int gety()                         //成员函数gety直接定义在类的内部
        {
            return y;
        }
    private:
        int x,y;
};

当然使用内联函数会减少函数调用的开销。定义函数的代码如下:

class Point
{
	public:
		inline void setpoint(int,int);                   //声明成员函数setpoint为内联函数 
	private:
		int x,y;
};
inline void Point::setpoint(int a,int b)                //在类外定义此函数为内联函数 
{
	x=a;
	y=b;
}

 3.对象的定义及使用

C++中的类的对象是对该类实例化的结果。

(1)对象的定义

有两种定义方式:

a.在声明类的同时,直接定义对象,即在声明类的右花括号“}”后。例如:

class Point
{
	public:
		void setpoint(int,int); 
		int getx();
		int gety();                  
	private:
		int x,y;
}op1,op2;                  //直接定义了对象op1和op2

 b.声明了类之后,在使用时再定义对象。基本格式如下:

类名 对象名1,对象名2,······;

例如:

Point op1,op2;

(2)对象中成员的访问

(a)通过对象名和对象选择符访问对象中的成员

一般形式为:

对象名.数据成员名

对象名.成员函数名[(实参表)] 

其中“.”叫做对象选择符,简称点运算符。

(b)通过指向对象的指针访问对象中的成员

例:

Date d,*ptr;

ptr=*d;

使用d.year或(*ptr).year或ptr->year三者等价。

(c)定义一个引用,通过引用来访问对象中的成员,其方法跟通过对象名来访问对象中的成员是相同的。

二.构造函数和析构函数

1.对象的初始化和构造函数

class Complex

{
double real=0.0;                            //在类声明中不能给数据成员赋初值

}

在定义对象时,对数据成员赋初值称为对象的初始化。

如果一个类的对象都是公有的,则可以在定义对象时对数据成员进行初始化。若类中包含私有的或者保护的成员,就不能用这种方法进行初始化。

所以一般用构造函数对数据进行初始化。构造函数的名字必须与类名相同他可以有任意类型的参数,但不可有返回值类型

构造函数的主要功能是对对象进行初始化,即对数据成员赋值。

在建立对象的同时,采用构造函数给数据成员赋值,通常采用以下两种形式:

(1)类名 对象名[(实参表)];

例:

complex(double r,double i)

{

real=r;

imag=i;

}
类型一:
complex A(1.1,2.2);

(2)类名*指针变量名=new类名[(实参表)];

这是一种用new运算符动态建立对象的方式。

说明:

(1)构造函数无返回值,在定义构造函数时,不能说明其类型。

(2)构造函数即可以定义在类内,也可以定义在类外。

定义在类外的情况如下:

Complex::Complex(double r,double i)
{
real=r;
imag=i;
}

(3)构造函数的作用主要是用来对对象进行初始化

(4)构造函数一般声明为公有成员,但它不需要也不能像其他成员函数一样被显式调用,他是在定义对象时被自动调用的,且只执行一次

(5)在实际应用中,通常要给每个类定义构造函数。如果没有定义构造函数,系统就会自动的生成一个默认的构造函数。

(6)构造函数还可以不带参数。如:

class Complex
{
    public:
        Complex()
        {
        real=0;
        imag=0;
        }
    private:
        double real,imag;
};

 2.用成员初始化列表对数据成员进行初始化

在声明类中,对数据成员的初始化工作一般是在构造函数中用赋值语句进行。

如:

class Complex
{
	private:
		double real,imag;
	public:
		Complex(double r,double i);
};
Complex::Complex(double r,double i)
{
	real=r;
	imag=i;	
} 

还有另一种方式——用成员初始化列表来实现对数据成员的初始化。如:

class Complex
{
	private:
		double real,imag;
	public:
		Complex(double r,double i);
};
Complex::Complex(double r,double i):real(r),imag(i)
{
}

带有初始化成员列表的构造函数的一般形式如下:
类名::构造函数名([参数表])[:(成员初始化列表)]

{

//构造函数体

}

成员初始化列表一般形式为:
数据成员名1(初始值1),数据成员名2(初始值2),······

对于const修饰的数据成员,或者是引用类型的数据成员,是不允许使用赋值语句直接赋值的。只能用成员的初始化列表对其进行初始化。

如:

#include<iostream>
using namespace std;
class A
{
	public:
		A(int x1):x(x1),rx(x),pi(3.14)
		{
		}
		void print()
		{
			cout<<"x="<<x<<"rx="<<rx<<"pi="<<pi<<endl;
		}
	private:
		int x;
		int& rx;
		const double pi;
};
int main()
{
	A a(10);
	a.print();
	return 0;
}

输出结果为:

x=10 rx=10 pi=3.14

数据成员是按照他们在类的声明中的顺序来进行初始化的,与他们在成员初始化列表中列出的顺序无关

3.构造函数的重载

C++允许构造函数重载,以便适应不同的场合。例:

#include<iostream>
using namespace std;
class Date
{
	public:
		Date();
		Date(int y,int m,int d);
		void showDate();
	private:
		int year;
		int month;
		int day;
};
Date::Date()
{
	year=2000;
	month=4;
	day=28;
}
Date::Date(int y,int m,int d):year(y),month(m),day(d) 
{
}
inline void Date::showDate()
{
	cout<<year<<"."<<month<<"."<<day<<endl; 
}
int main()
{
	Date date1;
	cout<<"Date1 output:"<<endl;
	date1.showDate();
	Date date2(2002,11,14);
	cout<<"Date2 output:"<<endl;
	date2.showDate();
	return 0;
}

运行结果如下:

注:

使用无参构造函数创建对象时,应该用语句“Date date1;”,而不能用语句“Date date1();”,因为语句“Date date1();”表示声明一个名为date1的普通函数,此函数的返回值为Date类型

4.带默认参数的构造函数

例:

#include<iostream>
#include<cmath>
using namespace std;
class Complex
{
	public:
		Complex(double r=0.0,double i=0.0);
		double abs();
	private:
	    double real,imag; 
};
Complex::Complex(double r,double i)
{
	real=r;
	imag=i;
}
double Complex::abs()
{
	double t;
	t=real*real+imag*imag;
	return sqrt(t);
}
int main()
{
	Complex s1;                               //没有传递实参,全用默认值
	cout<<"s1"<<s1.abs()<<endl;
	Complex s2(1.1);                          //传递了一个实参
	cout<<"s2"<<s2.abs()<<endl;
	Complex s3(1.1,2.2);                      //传递了两个实参
	cout<<"s3"<<s3.abs()<<endl;
	return 0;
}

说明:
(1)如果构造函数在类的声明外定义,那么默认参数应该在类的声明构造函数原型时指定,而不能在类外构造函数定义时指定

(2)如果构造函数的全部参数都指定了默认值,那么这时的构造函数也属于默认构造函数

(3)在一个类中定义了全部是默认参数的构造函数时,不能再定义重载构造函数

4.析构函数

析构函数常用于执行一些清理任务,如释放内存的分配空间

注:

(1)析构函数在他前面必须加一个波浪号(~)

(2)析构函数不返回任何值。不能说明其类型

(3)析构函数没有参数,不能被重载,一个类只能有一个析构函数

说明:

(1)每个类必须有一个析构函数

(2)除了在主函数结束之后,对象被撤销时,析构函数会被自动调用外,还有两种情况会被调用。

其一:如果一个对象被定义在函数体内,当这个函数调用结束之后,该对象会被释放,析构函数自动调用。

其二:若一个对象是使用new运算符动态创建的,则用delete来释放它时,delete会自动调用构造函数

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

CSS从入门到精通——动画:CSS3动画执行次数和逆向播放

目录 任务描述 相关知识 动画执行次数 动画反向播放 编程要求 任务描述 本关任务&#xff1a;用 CSS3 实现loading效果。效果图如下&#xff1a; 相关知识 为了完成本关任务&#xff0c;你需要掌握&#xff1a;1.动画执行次数&#xff0c;2.动画反向播放。 需要实现的效…

每天五分钟深度学习框架pytorch:多维tensor向量在某一维度的拼接和分割

本文重点 在深度学习中,我们常常需要完成多个向量拼接,同时也要完成向量的分割,在pytorch中已经有封装好的库,我们可以直接调用完成这部分任务。 Cat拼接 c=torch.cat([a,b],dim=0)表示将a和b按0维度进行拼接,需要注意再非dim维度,两个矩阵的维度必须是一致的,不然会拼…

docker拉取镜像一直在加载中,且会提示error pulling image configuration

1、增加国内镜像配置 #查看文件内容 sudo vim /etc/docker/daemon.json如果没有该文件&#xff0c;则需要在/etc/docker中创建一个daemon.json 文件 创建文件 vim daemon.json#文件中添加以下json {"registry-mirrors":["https://docker.mirrors.ustc.edu.cn/…

小工具开发

因不太喜欢重复性工作&#xff0c;为了提高日常工作效率&#xff0c;在业余时间开发一些小工具用于帮助自己“偷懒”。 小工具功能&#xff1a; 1、Hightec编译的hex文件&#xff0c;与多模式标定hex文件合成 2、Bootloader文件&#xff0c;Hightec编译的hex文件&#xff0c;与…

SpringMVC框架学习笔记(八):自定义拦截器和异常处理

1 自定义拦截器 1.1 什么是拦截器 1.1.1 说明 &#xff08;1&#xff09;Spring MVC 也可以使用拦截器对请求进行拦截处理&#xff0c;用户可以自定义拦截器来实现特定 的功能. &#xff08;2&#xff09;自定义的拦截器必须实现 HandlerInterceptor 接口 1.1.2 自定义拦截…

ssh的远程连接(Linux篇)

这里用到的虚拟机时centos7 记得提前先把网络连接好&#xff0c;这里选择的是桥接模式 1.启动ssh服务 # 在centos中启动sshd服务 sudo systemctl start sshd 2.在windows的cmd命令界面内输入以下内容 # ssh centos中的登录用户名centos中的IP地址 ssh yl192.168.1.108 然后…

Python 基础:类

目录 一、类的概念二、定义类三、创建对象并进行访问四、修改属性的值方法一&#xff1a;句点表示法直接访问并修改方法二&#xff1a;通过方法进行修改 五、继承继承父类属性和方法重写父类方法 六、将实例用作属性七、导入类导入单个类从一个模块中导入多个类导入整个模块导入…

效果超越ControlNet+IP-Adapter和FreeControl!Ctrl-X:可控文生图新框架(加州大学英伟达)

文章链接&#xff1a;https://arxiv.org/pdf/2406.07540 项目链接&#xff1a;https://genforce.github.io/ctrl-x/ 最近的可控生成方法&#xff0c;如FreeControl和Diffusion Self-guidance&#xff0c;为文本到图像&#xff08;T2I&#xff09;扩散模型带来了细粒度的空间…

机器学习(V)--无监督学习(一)聚类

根据训练样本中是否包含标签信息&#xff0c;机器学习可以分为监督学习和无监督学习。聚类算法是典型的无监督学习&#xff0c;目的是想将那些相似的样本尽可能聚在一起&#xff0c;不相似的样本尽可能分开。 相似度或距离 聚类的核心概念是相似度(similarity)或距离(distance…

模板方法模式和命令模式

文章目录 模板方法模式1.引出模板模式1.豆浆制作问题2.基本介绍3.原理类图 2.豆浆制作代码实现1.类图2.SoyaMilk.java 豆浆的抽象类3.PeanutSoyaMilk.java 花生豆浆4.RedBeanSoyaMilk.java 红豆豆浆5.Client.java6.结果 3.钩子方法1.基本介绍2.代码实现1.SoyaMilk.java 添加钩子…

数据中台-知识图谱平台

【数据分析小兵】专注数据中台产品领域,覆盖开发套件,包含数据集成、数据建模、数据开发、数据服务、数据可视化、数据治理相关产品以及相关行业的技术方案的分享。对数据中台产品想要体验、做二次开发、关注方案资料、做技术交流的朋友们&#xff0c;可以关注我。 1. 概述 随着…

弗洛伊德算法——C语言

弗洛伊德算法&#xff0c;是一种用于解决所有顶点对之间最短路径问题的经典算法&#xff0c;该算法通过动态规划的方法计算出从每个顶点到其他所有顶点的最短路径。 弗洛伊德算法的基本思想是逐步考虑每一个顶点作为中间点&#xff0c;更新所有顶点对之间的最短路径。它通过以…

开源模型应用落地-LangChain高阶-LCEL-表达式语言(七)

一、前言 尽管现在的大语言模型已经非常强大&#xff0c;可以解决许多问题&#xff0c;但在处理复杂情况时&#xff0c;仍然需要进行多个步骤或整合不同的流程才能达到最终的目标。然而&#xff0c;现在可以利用langchain来使得模型的应用变得更加直接和简单。 LCEL是什么&…

STM32CubeMX配置-RTC周期唤醒

一、简介 MCU为STM32G070&#xff0c;采用内部时钟32KHZ&#xff0c;配置为周期6s唤醒&#xff0c;调用回调函数&#xff0c;进行喂狗操作。 二、配置 初始时间、日期、周期唤醒时间配置。 开启周期唤醒中断 三、生成代码 调用回调函数&#xff0c;进行喂狗操作。 //RTC唤醒回…

vue-i18n使用步骤详解(含完整操作步骤)

开篇 下面是从创建vue项目开始&#xff0c;完整使用i18n实现国际化功能的步骤&#xff0c;希望对您有所帮助。 完整步骤 创建项目 创建项目&#xff0c;并在创建项目的时候选择vuex,router 选择3.x版本 后面随意选即可&#xff0c;下面是完整的代码结构 安装vue-i18n,并封装…

数据库事务隔离级别

前几天项目上合作公司的系统出现了一次死锁&#xff0c;突然想到由于近几年开发设计的系统并发用户比较少&#xff0c;很久没有碰到过死锁了&#xff0c;因此对死锁的概念也比较生疏了&#xff0c;需要温习一下。 事务 先从最基本的概念开始&#xff0c;事务、及其ACID特性。…

牛客热题:最长上升子序列(一)

&#x1f4df;作者主页&#xff1a;慢热的陕西人 &#x1f334;专栏链接&#xff1a;力扣刷题日记 &#x1f4e3;欢迎各位大佬&#x1f44d;点赞&#x1f525;关注&#x1f693;收藏&#xff0c;&#x1f349;留言 文章目录 牛客热题&#xff1a;最长上升子序列(一)题目链接方法…

浅谈赚钱的四个级别,你在哪一层呢

一谈到赚钱&#xff0c;很多人都会扯到&#xff1a;智商、情商、人脉、资源、背景等等&#xff0c;类似“小钱靠勤&#xff0c;中钱靠智&#xff0c;大钱靠德”这样的经典语录都会脱口而出&#xff0c;其实从本质上来讲&#xff0c;都没有错&#xff0c;但这样的说法太缥缈&…

基于CPS-SPWM链式STATCOM系统在电压不平衡环境下控制策略的simulink建模与仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 5.完整工程文件 1.课题概述 基于CPS-SPWM链式STATCOM系统在电压不平衡环境下控制策略的simulink建模与仿真。利用电压外环PI调节器得到有功 电流指令值结合由负载侧电流检测 到 的无功 电流指令值 &#…

element-plus表单组件之自动补全组件el-autocomplete和级联选择器组件el-cascader

el-autocomplete 自动补全组件 自补全组件的功能和可以根据输入过滤的el-select组件有些类似。 fetch-suggestions 根据输入框的输入获取建议的内容&#xff0c;其接受值是一个函数&#xff0c;有2个参数&#xff0c;querystring:输入的内容&#xff0c;callback内置函数&…