C++:类和对象(下)---对类和对象深入一些的理解

文章目录

  • 构造函数?
    • 初始化列表
    • explicit关键字
  • 匿名对象

构造函数?

初始化列表

前面已然介绍过构造函数,但并未完全结束,构造函数有很多种写法,有带缺省参数的,有全缺省的,不带缺省参数的…但用前面的方法,都是对里面成员变量的一种赋值,也就是说,这是给类中每一个成员变量一个初始值

但这并不是初始化,这里要分清楚什么是初始化,什么是赋初值
简单来说,它们的一个区别就是初始化只能初始化一次,但是赋值可以多次赋值

因此构造函数中就引入了初始化列表的概念,初始化列表可以做到给类内的成员函数初始化,下面写一个具体的例子来表示

#include <iostream>
using namespace std;class Date
{
public:Date(int year = 1900, int month = 1, int day = 1): _year(year), _month(month), _day(day){}void Print(){cout << _year << "/" << _month << "/" << _day << endl;}
private:int _year;int _month;int _day;
};

上面就是对初始化列表的概述,通过这样的写法可以对参数进行初始化

这里就体现了初始化和赋值的区别:

  1. 如果采用的是初始化,那么每个成员变量在初始化列表中只能初始化一次
  2. 类内如果有引用成员函数,const成员变量和自定义成员且没有默认构造函数时,就要写在初始化列表的位置
  3. 尽量使用初始化列表进行初始化,不管是否用初始化列表,对于自定义类型的成员变量都会先使用初始化列表进行初始化
  4. 成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关

下面来对第二条进行解读,同时也能更好的理解上面的原理

  1. 有const成员变量
#include <iostream>
using namespace std;class Date
{
public://Date(int year = 1900, int month = 1, int day = 1)//	: _year(year)//	, _month(month)//	, _day(day){}Date(int year = 1900, int month = 1, int day = 1, int tmp = 1){_year = year;_month = month;_day = day;_tmp = tmp;}void Print(){cout << _year << "/" << _month << "/" << _day << endl;}
private:int _year;int _month;int _day;const int _tmp;
};

这里的构造函数对吗?很显然是不能编译通过的,原因也很简单,这里的_tmp是const修饰的变量,怎么能给它赋值?解决方法有两个,第一个是可以给它在声明的时候就给它一个值,这是可以的,但使用初始化列表可以完美解决这个问题

#include <iostream>
using namespace std;class Date
{
public:Date(int year = 1900, int month = 1, int day = 1, int tmp = 1): _year(year), _month(month), _day(day), _tmp(tmp) {}//Date(int year = 1900, int month = 1, int day = 1, int tmp = 1)//{//	_year = year;//	_month = month;//	_day = day;//	//_tmp = tmp;//}void Print(){cout << _year << "/" << _month << "/" << _day << endl;cout << "const tmp  " << _tmp << endl;;}
private:int _year;int _month;int _day;const int _tmp = 1;
};

这里也能更好理解赋值和初始化的区别,从const上就可以很好的体现出来

  1. 引用

还有一大使用场景就是在引用中可以体现,这里就不再写错误的示范了

class Date
{
public:Date(int year = 1900, int month = 1, int day = 1, int tmp = 1): _year(year), _month(month), _day(day), _tmp(tmp) {}//Date(int year = 1900, int month = 1, int day = 1, int tmp = 1)//{//	_year = year;//	_month = month;//	_day = day;//	//_tmp = tmp;//}void Print(){cout << _year << "/" << _month << "/" << _day << endl;cout << "const tmp  " << _tmp << endl;;}
private:int _year;int _month;int _day;int& _tmp;
};

explicit关键字

C++提供了关键字explicit,可以阻止不应该允许的经过转换构造函数进行的隐式转换的发生,声明为explicit的构造函数不能在隐式转换中使用

在了解explicit前,就必须先知道隐式转换是什么了
显式转换一定不陌生,就是强行转换,因此隐式转换就是编译器自动发生转换
比如说下面这样的例子:

int main()
{int i = 0;double d = 1.2;int& p = d;return 0;
}

这里编译是通不过的,原因是因为d是double类型因此编译不通过吗?其实不然

在这里插入图片描述
在编译器的处理中,会把d先生成一个临时变量,再进行赋值,而我们都知道临时变量是具有常性的,因此这里并不能把一个常属性的数交给引用来处理

因此这里只需要加上const,进行权限的缩小,就可以用常引用接纳常性变量了

const int& p = d;

其实,上述过程中把变量d从double类型转换到int类型就是一个隐式类型转换,我们并没有进行转换,但是编译器依旧自己转换了,并且生成了临时变量导赋值失败

而explicit的存在就是不能让隐式转换存在,因此我们不能把类型局限在int和double类型,要加入类的类型

class A
{
public:A(int a = 10) :_a(a) {}
private:int _a;
};int main()
{A a;a = 2;return 0;
}

看看上面的代码发生了什么?把2赋给了一个类?如果你知道了隐式类型转换,那么就不难理解这段代码,这就是把2进行隐式类型转换,把它转换成了类A,里面成员变量_a的值是2,然后又进行了一次赋值

那么explicit就可以登场了,在初始化列表前面加上explicit:

class A
{
public:explicit A(int a = 10) :_a(a) {}
private:int _a;
};int main()
{A a;a = 2;return 0;
}

此时,隐式转换就不存在了,因此这里的赋值就不复存在了,因为2在这里真的就是一个数字2

匿名对象

C++中引入了匿名对象的概念,简单来说就是没有名字的对象

class A
{
public:explicit A(int a = 10) :_a(a) {}
private:int _a;
};int main()
{A(2);return 0;
}

这里看起来很奇怪,但这是可以通过的,C++内部是允许这样做的,它和有名对象的区别在于:
匿名对象的生命周期只在这一行,结束后就进行析构,而正常生成的对象需要在main函数结束后才会进行析构,普通生成的对象的生命周期是它的局部域

那匿名对象有什么用?

假设有这样的情景

class A
{
public:explicit A(int a = 10) :_a(a) {}void Print(){cout << "Print" << endl;}
private:int _a;
};int main()
{A a1;a1.Print();A().Print(); // 匿名对象return 0;
}

假如这里我只需要调用类内的成员函数print,但如果正常来说我是需要创建一个对象,再通过对象去引用这个类内的成员函数,这是十分繁琐的,如果使用匿名对象,我不关注这个对象是谁,这个对象是多少,我只关心能不能引用类内的成员函数,因此就可以这样使用,相比起使用定义对象的方法来看,这样的方法的生命周期更短

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

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

相关文章

Linux下查找python路径

本地目前装了几个版本的python&#xff0c;这里记录下查找python路径的方法。 1&#xff1a;whereis命令 whereis python2&#xff1a;which命令 which python与whereis相似&#xff0c;但which会返回第一个找到的执行文件的位置。 3&#xff1a;find命令 find命令可以搜索系…

web流程自动化详解

今天给大家带来Selenium的相关解释操作 一、Selenium Selenium是一个用于自动化Web浏览器操作的开源工具和框架。它提供了一组API&#xff08;应用程序接口&#xff09;&#xff0c;可以让开发人员使用多种编程语言&#xff08;如Java、Python、C#等&#xff09;编写测试脚本&…

需求分析案例:消息配置中心

本文介绍了一个很常见的消息推送需求&#xff0c;在系统需要短信、微信、邮件之类的消息推送时&#xff0c;边界如何划分和如何设计技术方案。 1、需求 一个系统&#xff0c;一般会区分多个业务模块&#xff0c;并拆分成不同的业务系统&#xff0c;例如一个商城的架构如下&am…

day45-Netflix Mobile Navigation(左边侧边栏动态导航)

50 天学习 50 个项目 - HTMLCSS and JavaScript day45-Netflix Mobile Navigation&#xff08;左边侧边栏动态导航&#xff09; 效果 index.html <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name&…

33. 本地记事本

本地记事本 html部分 <button class"add"><i class"iconfont icon-jiahao"></i> </button>css部分 *{margin: 0;padding: 0; } body{background-color: #7bdaf3;display: flex;padding-top: 3rem;flex-wrap: wrap; } .add{pos…

每日一题——删除有序数组中的重复项

删除有序数组中的重复项 题目链接 注&#xff1a;本题所采用的方法是建立在移除元素的基础之上的&#xff0c;如果大家对双指针的方法不大了解&#xff0c;或者不会做《移除元素》这一题&#xff0c;建议先去看看&#x1f449;传送门 具体步骤 定义两个指针slow和fast&#…

【计算机网络】传输层协议 -- UDP协议

文章目录 1. 传输层相关知识1.1 端口号1.2 端口号范围划分1.3 知名端口号1.4 一些相关命令 2. UDP协议2.1 UDP协议格式2.2 UDP协议的特点2.3 什么是面向数据报2.4 UDP的缓冲区2.5 UDP使用注意事项2.6 基于UDP的应用层协议 1. 传输层相关知识 传输层是计算机网络中的一个重要层…

【如何训练一个中英翻译模型】LSTM机器翻译模型部署之onnx(python)(四)

系列文章 【如何训练一个中英翻译模型】LSTM机器翻译seq2seq字符编码&#xff08;一&#xff09; 【如何训练一个中英翻译模型】LSTM机器翻译模型训练与保存&#xff08;二&#xff09; 【如何训练一个中英翻译模型】LSTM机器翻译模型部署&#xff08;三&#xff09; 【如何…

云原生架构

1. 何为云原生&#xff1f; 很多IT业内小伙伴会经常听到这个名词&#xff0c;那么什么是云原生呢&#xff1f;云原生是在云计算环境中构建、部署和管理现代应用程序的软件方法。 当今时代&#xff0c;众多企业希望构建高度可扩展、灵活且有弹性的应用程序&#xff0c;以便能够快…

13 亿美金买个寂寞?No!AI 时代的数据行业蓄势待发

6月底&#xff0c;全球数据分析领域彻底炸锅了。 两大数据分析企业Databricks和Snowflake纷纷将目光瞄准了AI大模型。要知道&#xff0c;这两位对手平时没少对台戏&#xff0c;为性能、产品和技术经常开撕。但在今年的自家大会上&#xff0c;两家企业却出奇的一致&#xff0c;…

云安全攻防(二)之 云原生安全

云原生安全 什么是云原生安全&#xff1f;云原生安全包含两层含义&#xff1a;面向云原生环境的安全和具有云原生特征的安全 面向云原生环境的安全 面向云原生环境的安全的目标是防护云原生环境中的基础设施、编排系统和微服务系统的安全。这类安全机制不一定会具有云原生的…

Java 设计模式 - 简单工厂模式 - 创建对象的简便之道

简单工厂模式是一种创建型设计模式&#xff0c;它提供了一种简单的方式来创建对象&#xff0c;而无需暴露对象创建的逻辑。在本篇博客中&#xff0c;我们将深入了解简单工厂模式的概念、实现方式以及如何在Java中使用它来创建对象。 为什么使用简单工厂模式&#xff1f; 在软…

【无标题】深圳卫视专访行云创新马洪喜:拥抱AI与云原生,深耕云智一体化创新

人工智能&#xff08;AI&#xff09;是引领新一轮科技革命和产业变革的重要驱动力。因此&#xff0c;深圳出台相关行动方案&#xff0c;统筹设立规模1,000亿元的人工智能基金群&#xff0c;引导产业集聚培育企业梯队&#xff0c;积极打造国家新一代人工智能创新发展试验区和国家…

【高压架构】AP5199S LED平均电流型恒流驱动IC 0.01调光 景观舞台汽车灯驱动照明

说明 AP5199S 是一款外围电路简单的多功能平均电流型 LED 恒流驱动器&#xff0c;适用于宽电压范围的非隔离式大功率恒流 LED 驱动领域。芯片 PWM 端口支持超小占空比的 PWM 调光&#xff0c;可响应 60ns 脉宽。为客户提供解决方案&#xff0c;限度地发挥灯具优势&#xff0c;…

shell中按照特定字符分割字符串,并且在切分后的每段内容后加上特定字符(串),然后再用特定字符拼接起来

文件中的内容&#xff0c;可以这么写&#xff1a; awk -F, -v OFS, {for(i1;i<‌NF;i){$i$i"_suffix"}}1 input.txt-F,&#xff1a;设置输入字段分隔符为逗号&#xff08;,&#xff09;&#xff0c;这将使awk按照逗号分割输入文本。-v OFS‘,’&#xff1a;设置输…

【Golang】Golang进阶系列教程--为什么 Go 不支持 []T 转换为 []interface

文章目录 前言官方解释内存布局程序运行中的内存布局通用方法 前言 在 Go 中&#xff0c;如果 interface{} 作为函数参数的话&#xff0c;是可以传任意参数的&#xff0c;然后通过类型断言来转换。 举个例子&#xff1a; package mainimport "fmt"func foo(v inter…

python 面向对象编程的特点 - 封装 - 继承(经典类、新式类) - 多态 - 静态方法、类方法 - 下划线的使用 - 回合制攻击游戏实验

目录 面向对象编程的特点&#xff1a; 封装&#xff1a;封装是将数据和操作&#xff08;方法&#xff09;封装在一个对象中的能力 继承&#xff1a;继承是指一个类&#xff08;子类&#xff09;可以继承另一个类&#xff08;父类&#xff09;的属性和方法。 我们为什么需要继…

HashMap中hash方法的作用(详解)

首先&#xff0c;hash方法用来干什么&#xff1f; 在搞清楚原理之前&#xff0c;我们先站在巨人的肩膀浅浅了解一下hash方法的本质作用。 实质上&#xff0c;它的作用很朴素&#xff0c;就是用key值通过某种方式计算出一个hash码 而且这个hash码我们后面要用来计算key存在底…

golangd\pycharm-ai免费代码助手安装使用gpt4-免费使用--[推荐]

golangd-ai免费代码助手安装使用,pycharm可以使用&#xff0c;估计只要是xx的ide都是可以使用这个插件 目前GPT4以及gpt的大规模使用&#xff0c;如何快速掌握以及在ide中快速使用的办法&#xff0c;今天安装一款golangd编辑器的插件已经使用 一、安装以及使用 1.在golangd中…

贼全! 一举通关的 Spring+SpringBoot+SpringCloud 全攻略, 是真香啊

前几天&#xff0c;有幸从朋友那里得到了一份 Alibaba 内部的墙裂推荐的“玩转 Spring 全家桶的 PDF”&#xff0c;我也不是个吝啬的人&#xff0c;好的东西当然要一起分享。那今天我就秀一把&#xff0c;带你一站通关 Spring、Spring Boot 与 Spring Cloud,让你轻松斩获大厂 O…