首页 > 其他分享 >类和对象(中)

类和对象(中)

时间:2024-06-16 16:59:06浏览次数:7  
标签:函数 对象 默认 运算符 编译器 重载 构造函数

学习目标:

1. 类的6个默认成员函数

2. 构造函数

3. 析构函数

4. 拷贝构造函数

5. 赋值运算符重载

6. const成员函数

7. 取地址及const取地址操作符重载


学习内容:

一.类的6个默认成员函数

如果一个类中什么成员都没有,简称为空类。

空类中真的什么都没有吗?并不是,任何类在什么都不写时,编译器会自动生成以下6个默认成员函数。

默认成员函数:用户没有显式实现,编译器会生成的成员函数称为默认成员函数。

1. 构造函数

1.1

  构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,以保证每个数据成员都有 一个合适的初始值,并且在对象整个生命周期内只调用一次。

1.2 特性

构造函数是特殊的成员函数,需要注意的是,构造函数虽然名称叫构造,但是构造函数的主要任务并不是开空间创建对象,而是初始化对象。

其特征如下:

1.函数名与类名相同

2.无返回值。

3.对象实例化时自动调用对应的构造函数

4.构造函数可以重载

5.如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦用户显式定义编译器将不再生成。

讨论: 关于编译器生成的默认成员函数,很多童鞋会有疑惑:不实现构造函数的情况下,编译器会生成默认的构造函数。但是看起来默认构造函数又没什么用?d对象调用了编译器生成的默认构造函数,但是d对象_year/_month/_day,依旧是随机值。也就说在这里编译器生成的默认构造函数并没有什么用??

解答:C++把类型分成内置类型(基本类型)和自定义类型。内置类型就是语言提供的数据类型,如:int/char...,自定义类型就是我们使用class/struct/union等自己定义的类型,看看下面的程序,就会发现编译器生成默认的构造函数会对自定类型成员_t调用的它的默认构造函数。

注意:C++11 中针对内置类型成员不初始化的缺陷,又打了补丁,即:内置类型成员变量在类中声明时可以给默认值。所以,当类中有自定义类型时,无需定义构造函数,使用编译器的默认构造函数即可,成员变量的初始化在声明时给出。

6.无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个。

注意:无参构造函数、全缺省构造函数、我们没写编译器默认生成的构造函数,都可以认为是默认构造函数。

2.析构函数

2.1概念

析构函数:与构造函数功能相反,析构函数不是完成对对象本身的销毁,局部对象销毁工作是由编译器完成的。而对象在销毁时会自动调用析构函数,完成对象中资源的清理工作。

3.2 特性

析构函数是特殊的成员函数,其特征如下: 

1. 析构函数名是在类名前加上字符 ~。

2. 无参数无返回值类型。 

3. 一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。注意:析构函数不能重载

4. 对象生命周期结束时,C++编译系统系统自动调用析构函数。

5.编译器生成的默认析构函数,对自定类型成员调用它(自定义类型)的析构函数。


6.如果类中没有申请资源时,析构函数可以不写,直接使用编译器生成的默认析构函数,比如Date类;有资源申请时,一定要写,否则会造成资源泄漏,比如Stack类。

当既申请了资源又有自定义类型时,可以通过定义的析构函数清理资源,同时自定义类型的清理会通过调用其内的析构函数

注意:

无论是默认构造(析构)函数还是显示定义的构造(析构)函数,对于自定义类型(类对象)都会调用它的默认构造函数(析构函数)。

三.拷贝构造函数

3.1 概念

拷贝构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类类型对象创建新对象时由编译器自动调用。(实际是拷贝初始化)

3.2 特征

1. 拷贝构造函数是构造函数的一个重载形式。 

2. 拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错,因为会引发无穷递归调用。

3. 若未显式定义,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。

注意:在编译器生成的默认拷贝构造函数中,内置类型是按照字节方式直接拷贝的,而自定义类型是调用其拷贝构造函数完成拷贝的。

注意:类中如果没有涉及资源申请时,拷贝构造函数是否写都可以;一旦涉及到资源申请时,则拷贝构造函数是一定要写的,否则就是浅拷贝。

4. 拷贝构造函数典型调用场景:

使用已存在对象创建新对象

函数参数类型为类类型对象

函数返回值类型为类类型对象

四.赋值运算符重载

4.1 运算符重载(可放在全局也可在类域中,编译时优先到类域查找)

  C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。

函数名字为:关键字operator后面接需要重载的运算符符号。

函数原型:返回值类型 operator操作符(参数列表)

  注意:

(1)不能通过连接其他符号来创建新的操作符:比如operator@ 

(2)重载操作符必须有一个类类型参数

(3)用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不 能改变其含义 

(4)作为类成员函数重载时,其形参看起来比操作数数目少1,是因为成员函数的第一个参数为隐藏的this

(5).* :: sizeof ?: . 注意以上5个运算符不能重载。这个经常在笔试选择题中出

现。

注意:

运算符重载一般都放在类中声明,因为类对象中的成员变量一般都私密,放在类中就可以访问了。

4.2赋值运算符重载

(1). 赋值运算符重载格式

*参数类型:const T&,传递引用可以提高传参效率

*返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值

*检测是否自己给自己赋值

*返回*this :要复合连续赋值的含义

(2)赋值运算符只能重载成类的成员函数不能重载成全局函数

原因:赋值运算符如果不显式实现,编译器会生成一个默认的。此时用户再在类外自己实现一个全局的赋值运算符重载,就和编译器在类中生成的默认赋值运算符重载冲突了,故赋值运算符重载只能是类的成员函数。

(3)用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝。

注意:内置类型成员变量是直接赋值的,而自定义类型成员变量需要调用对应类的赋值运算符重载完成赋值。

注意:如果类中未涉及到资源管理,赋值运算符是否实现都可以;一旦涉及到资源管理则必须要实现。这一点和拷贝构造函数类似。

4.3 前置++和后置++重载

五.const成员

 (1)  将const修饰的“成员函数”称之为const成员函数,const修饰类成员函数,实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改。

(2)取地址及const取地址操作符重载

这两个运算符一般不需要重载,使用编译器生成的默认取地址的重载即可,只有特殊情况,才需要重载,比如想让别人获取到指定的内容!

六.流插入和流提取(<<)

  前面了解了运算符的重载,且知到cout和cin加“<<”可以自行转化类型,但这只限于内置类型,那么可不可以cout<<"类对象"呢?这就需要对<<进行重载,

比如我们想直接把自定义类型d1打印出来,如下所示

解读:

1.函数放在了全局域,实际上也可以放在类域里,但由于函数重载的参数顺序和操作数顺序是一致的,如果放在类里,*this永远是第一个参数,这样就只能写成d2<<cout,显然不合适,但放在全局域就可以了,但此时面临一个新难题:无法访问私有变量。用友元就可以解决。

2.返回类型是输出流ostream,是为了适用于链式调用:cout<<d1<<d2


标签:函数,对象,默认,运算符,编译器,重载,构造函数
From: https://blog.csdn.net/2302_79440910/article/details/139722301

相关文章

  • C++面向对象三大特性
    C++三大特性包括了封装、继承、多态。封装:封装是将数据属性和操作这些数据的函数(方法)捆绑在一起的过程。它隐藏了实现细节,只暴露出一个可以被外界访问的接口。封装允许开发者将对象的实现细节保护起来,只提供必要的操作界面,从而减少错误和提高代码的可维护性。继承:继承是一种......
  • 要将URL参数转换为JSON对象,可以使用以下函数:
    要将URL参数转换为JSON对象,可以使用以下函数:javascriptfunctiongetQueryParams(url){//使用正则表达式提取URL参数constparamsString=url.split('?')[1];if(!paramsString){return{};}//将参数字符串分割成数组,并解析键值对constparams=......
  • 面向对象 这一文拿捏了 ⭐ (建议收藏)
    面向对象中级部分已整理完成,建议收藏......
  • 第一百零九节 Java面向对象设计 - Java抽象类和方法
    Java面向对象设计-Java抽象类和方法Java可以定义一个类,其对象不能被创建。它的目的只是表示一个想法,这是其他类的对象共有的。这样的类称为抽象类。语法我们需要在类声明中使用 abstract 关键字来声明一个抽象类。例如,下面的代码声明一个Shape类的抽象:publicabstr......
  • flask中cbv加装饰器、闪现(flash)、g对象、蓝图、flask-session、wtforms
    开源项目,可写在简历里1#开源项目sql审核平台2-https://gitee.com/cookieYe/Yearning3-https://gitee.com/rtttte/Archery cbv加装饰器1fromflaskimportFlask2fromflask.viewsimportMethodView34app=Flask(__name__)56app.debug=True7......
  • C# 对象克隆(深拷贝,不引用对象源的内存地址)
    对象克隆拓展方法:///<summary>///深度克隆对象///</summary>///<typeparamname="T">要克隆的类型</typeparam>///<paramname="obj">要克隆的实体</param>///<returns>返回克隆到的实体</returns>publicstaticTClone<......
  • 支付宝spi接口设计验签和返回结果加签注意点,支付宝使用JSONObject对象
    支付宝spi接口设计验签和返回结果加签注意点,支付宝使用JSONObject对象SPI三方服务接入指南https://opendocs.alipay.com/isv/spiforisv服务端实现Demo以下Demo是通过Java实现的SPI服务样例,包括验签支付宝请求报文、业务逻辑处理、商家加签以及响应报文构造的逻辑。......
  • JVM中的对象
    虚拟机中的对象对象的分配虚拟机遇到一条new指令时:根据new的参数是否能在常量池中定位到一个类的符号引用,如果没有,说明还未定义该类,抛出ClassNotFoundException1)检查加载先执行相应的类加载过程。如果没有,则进行类加载2)分配内存根据方法区的信息确定为该类分配的内存空......
  • 【C++】类和对象(下)
    【C++】类和对象(下)初始化列表构造时的类型转化static成员概念特性友元友元函数友元类内部类匿名对象总结初始化列表在对类和对象有了基本的认识之后,可以知道在创建对象的时候,编译器通过调用构造函数,给对象中各个成员变量一个合适的初始值。classDate{public: ......
  • 【C++ | const成员】一文了解类的 const数据成员、const成员函数、const对象、mutable
    ......