C++初阶:类与对象(尾篇)

目录

  • 1. 构造函数与初始化列表
    • 1.1 对象的创建与构造函数的初始化
    • 1.2 初始化列表及构造函数存在的意义
    • 1.3 explicit关键字与构造函数的类型转换
  • 2. static成员变量与static成员函数
    • 2.1 static成员变量
    • 2.2 static成员函数
  • 3. 日期类流插入操作符的重载与友元
    • 3.1 友元
    • 3.2 友元函数
    • 3.3 友元类
  • 4. 内部类
  • 5. 匿名对象
  • 6. 拷贝对象时编译器可能会进行的一些优化

1. 构造函数与初始化列表

1.1 对象的创建与构造函数的初始化

  1. 在前面的学习中,我们尝试了对简单类(日期类)进行了实现,而后在使用中我们通过定义类模板然后实例化的方式,创建我们所需要的对象。
  2. 在这一过程中,编译器按照所指定的类型去相应的内存区域中申请空间,在已经创建好变量后,再调用构造函数对生成的对象进行初始化。
  3. 大多数情况下,这种初始化的方式都不会出现问题,可是当类的成员变量中有一些特定的类型比如,const修饰的变量引用类型的变量没有默认构造函数的自定义类型,此时,这种初始化方式就行不通了。(默认构造函数:编译器自动生成,无参数,有缺省参数)

1.2 初始化列表及构造函数存在的意义

  1. 内置类型可以在创建变量申请空间时就进行变量的初始化,而自定义类型是否也可以在创建变量的同时就进行初始化,它的初始化方式是什么,接下来,我们引出类与对象中的初始化列表。
  2. 类实例化生成对象时并不是只开辟空间,对空间中的内容不做处理,而是会调用初始化列表对开辟出的空间进行初始化。前面之所以无法对特殊类型无法进行初始化,是因为我们没有向初始化列表中添加内容。
  1. 初始化列表的定义方式:
//构造函数
class A
{
private:int _a;int _b;int _c//构造函数,函数体之前,语法如下:A(int a, int b ,int c):_a(a),_b(b),_c(c){}
}
  1. 初始化列表的调用方式:(三种必须用初始化列表进行初始化的成员变量)
//没有缺省参数
class A
{
public:A(int d){_d = d;}int _d;
};class B
{
public:const int _a;int& _b;A _c;//构造函数B(int b, int c):_a(10),_b(b),_c(c){cout << " _a = " << _a << " _b = " << _b << " _c._d = " << _c._d << endl;}
};int main()
{int b = 20;int c = 30;B a(b, c);return 0
}
  1. 初始化列表初始化成员变量的顺序:
    初始化列表进行初始化的顺序是根据成员变量的声明顺序决定的
class A
{
public:int _b;int _a;//先初始化_a,再初始化_bA(int a = 0):_a(a),_b(_a){}void Print(){cout << _a << ' ' << _b << ' ' << endl;}
};int main()
{A a(10);a.Print();return 0;
}

执行结果:使用成员变量_a初始化成员变量_b时,_a还没有被初始化
在这里插入图片描述

  1. <1> 既然初始化列表可以进行初始化,并且初始化列表能做到构造函数无法做到的特殊类型成员的声明,那么,为什么还要有构造函数呢?
    <2> 初始化列表能做的只有初始化,无法对初始化后的变量做检查与合法性判断
class A
{
public:int* _a;A(int n):_a((int*)malloc(n * sizeof(int))){if (_a == nullptr){perror("malloc failed");exit(-1);}}
};

1.3 explicit关键字与构造函数的类型转换

  1. 类的默认成员函数operator=重载,其构造函数在只有单参数或拥有缺省参数,支持用与成员变量类型相同的数据,变量直接进行赋值操作。
class Date
{
public:int _year;int _month;int _day;Date(int year, int month = 1, int day = 1):_year(year),_month(month),_day(day){}Date& operator=(const Date& d){if (this != &d){_year = d._year;_month = d._month;_day = d._day;}return *this;}
};int main()
{Date d1(2024);d1 = 2025;int year = 2026;d1 = year;cout << d1._year << '-' << d1._month << '-' << d1._day << endl;return 0;
}

支持上述操作的原因,是因为数据或者变量会进行类型转换构造临时对象,然后再用临时构造出的对象进行赋值操作

  1. explicit关键字,修饰构造函数,使得这个构造函数所在的类其,实例化的对象不会发生类型转换的操作。
class Date
{
public:int _year;int _month;int _day;explicit Date(int year, int month = 1, int day = 1):_year(year),_month(month),_day(day){}
};

2. static成员变量与static成员函数

2.1 static成员变量

  1. 静态成员变量也是类的成员之一,它不独属于某个对象,而是属于这个类,为所有实例化对象所共有,存放在静态区。
  2. 静态成员变量在类中声明,在类外定义,在类外定义时不需要加static关键字。
  3. 静态成员变量的调用方式为,对象.静态成员变量类区域::静态成员变量
  4. 静态成员变量也受访问限定符的限制
class A
{
public:static int _count;A(){++_count;}A(const A& a){++_count;}~A(){--_count;}
};int A::_count = 0;int main()
{A a1;cout << a1._count << endl;a1.~A();cout << A::_count << endl;return 0;
}

2.2 static成员函数

  1. 与静态成员变量类似,静态成员函数也是属于全体实例化对象,而不是属于某个对象。
  2. 静态成员函数的定义方式,也是类内声明类外定义。
  3. 静态成员函数没有this指针,不能调用非静态成员变量。
  4. 静态成员函数的调用方式,对象.静态成员函数类域::静态成员函数
  5. 同样的静态成员函数也受访问限定符限制。
class A
{
//public:static int _count;static int GetCount();
public://非静态成员函数可以调用静态成员函数void Print(){cout << (*this).GetCount() << endl;cout << "hello" << endl;}A(){++_count;}A(const A& a){++_count;}~A(){--_count;}
};int A::_count = 0;
int A::GetCount()
{//静态成员函数没有this指针//无法调用非静态成员函数return A::_count;
}

3. 日期类流插入操作符的重载与友元

  1. 当我们尝试对实现过的日期类进行流插入运算的重载时,当把它作为成员函数时,我们发现无法实现。
  2. 操作数的次序为操作符重载函数的参数从左往右,分别是操作符的第一个,第二个…操作数。
  3. 成员函数的一个参数都为隐藏的默认参数this指针,而流插入操作符的需要的第一个参数是ostream类型的变量。可是,当我们不使用成员函数的方式实现,那么函数就无法访问private访问限定符修饰的成员变量。
  1. 那么,流插入操作符的重载就无法实现吗,这里我们引入C++新的内容,友元

3.1 友元

  1. 友元关系的实际应用分为友元类与友元函数,这是一种突破类访问限定符封装的方式,它在提供了这种功能的同时,也不可避免地增加了代码的耦合性,不建议多用。

3.2 友元函数

  1. 友元函数是普通函数,它定义在类外。而它达成友元的方式为,在类中对其进行友元声明。
  2. 友元函数可以在类中的任何地方声明,不受访问限定符影响。
  3. 友元函数的声明方式为,在普通的函数声明前加关键字friend
  4. 一个函数可以是多个类的友元函数。
class Date
{
public:int _year;int _month;int _day;Date(int year, int month = 1, int day = 1):_year(year),_month(month),_day(day){}friend ostream& operator<<(ostream& out, const Date& d);friend istream& operator>>(istream& out, const Date& d);
};ostream& operator<<(ostream& out, const Date& d)
{out << d._year << '-' << d._month << '-' << d._day;return out;
}istream& operator>>(istream& in, Date& d)
{in >> d._year >> d._month >> d._day;return in;
}

3.3 友元类

  1. 友元类的所有成员函数都是另一个类的友元函数,可以访问另一个类的所有私有成员。
  2. 友元类关系是单向的。
  3. 友元关系不可传递,A类是B类友元,B类是C类的友元,A类不是C类的友元,不可以访问C类。
  4. 友元关系不能被继承
  5. 友元类的声明方式为,在需要被访问的类中声明其的友元类,friend + 类名
class Time
{
public:Time(int hour = 0, int minute = 0, int seconds = 0):_hour(hour), _minute(minute), _seconds(seconds){}friend class Date;private:int _hour;int _minute;int _seconds;
};class Date
{
public:int _year;int _month;int _day;Time _t;Date(int year, int month = 1, int day = 1):_year(year),_month(month),_day(day){}void SetTime(){_t._hour = 21;_t._minute = 25;_t._seconds = 0;cout << _t._hour << '/' << _t._minute << '/' << _t._seconds << endl;}
};

4. 内部类

  1. 如果一个类定义在另一个类的内部,这个内部类就叫做内部类。
  2. 外部类对内部类没有访问权限。
  3. 内部类只是在外部类中声明,外部类计算大小时不包含内部。(sizeof(外部类)单纯只是外部类的大小)
  4. 内部类对外部类天生就是友元,并且可以直接访问外部类的静态成员变量与函数,无需指定类域。
  5. 内部类可以在任意访问限定符的区域声明,在private中时,无法进行内部类的调用实例化对象。
class A
{
private:int _a;static int _c;public:class B{public:void test(A& x){x._a = 10;_c = 20;cout << x._a << endl;cout << x._c << endl;}};
};int A::_c = 0;int main()
{A x;//內部类对象的声明A::B h;h.test(x);return 0;
}

5. 匿名对象

  1. 在实例化对象时,省略对象名的创建方式。
  2. 匿名对象的声明周期只有一行,紧接着下一行时,就会调用析构函数将其销毁。
class A
{
private:int _ a;
public:A(int a = 0){cout << _a << endl;}void Print(){cout << "hello world" << endl;	}
};//不支持此种调用构造函数的方式,因为无法识别其为函数的声明还是析构函数的调用
A a1();//创建匿名对象的方式
A();//匿名对象调用成员函数
A().Print();

6. 拷贝对象时编译器可能会进行的一些优化

  1. 在成员函数传参和传返回值的过程中,一般编译器会做一些优化,减少不必要对象的拷贝
  2. 在同一行中,连续的构造,拷贝构造操作编译器会进行优化:(同一表达式中)
    <1> 构造 + 拷贝构造 优化为 构造
    <2> 构造 + 构造 优化为 构造
    <3> 连续的拷贝构造 优化为 直接进行拷贝构造
    (临时对象,匿名对象生命周期只有一行)
class C
{
private:int _c;
public:C(int c){cout << "C()" << endl;}C(const C& tmp){cout << "C(const C&)" << endl;}
};void f1(C aa)
{}C f2()
{C aa;return aa;
}int main()
{//构造 + 拷贝构造,类型转换,生成临时对象C c1(2);//构造 + 拷贝构造 => 构造f1(C(2));//连续的拷贝构造 =>直接进行拷贝构造C c3 = f2();//不会优化,需要引用中间变量const C& c4 = 2;//不会优化,没有在同一表达式中C c5(2);f1(c5);return 0;
}

补充练习:(内部类,访问限定符) 在这里插入图片描述

  1. 求n!
  2. 思路:创建对应数量的对象,在构造函数中++静态成员变量,使用静态成员变量计数
class Solution 
{
private:static int _ret;static int _i;//将内部类定义在private下可保证不被非法访问class B{//默认为私有public:B(){_i++;_ret += _i;}};public:int Sum_Solution(int n) {//将类B设为公有,即可在外部类访问B arr[n];return  _ret;}};int Solution::_i = 0;
int Solution::_ret = 0;

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

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

相关文章

基于openresty构建运维工具链实践

本文字数&#xff1a;4591字 预计阅读时间&#xff1a;25 01 导读 如今OpenResty已广泛被各个互联网公司在实际生产环境中应用&#xff0c;在保留Nginx高并发、高稳定等特性基础上&#xff0c;通过嵌入Lua来提升在负载均衡层的开发效率并保证其高性能。本文主要介绍接口鉴权、流…

前端基础——HTML傻瓜式入门(1)

该文章Github地址&#xff1a;https://github.com/AntonyCheng/html-notes 在此介绍一下作者开源的SpringBoot项目初始化模板&#xff08;Github仓库地址&#xff1a;https://github.com/AntonyCheng/spring-boot-init-template & CSDN文章地址&#xff1a;https://blog.c…

ThingsBoard Edge 安装部署

文章目录 一、概述1.官方文档2.部署说明3.安装准备3.1. 克隆服务器3.2.安装 Docker3.3.安装 Java 113.4.安装 PostgreSQL3.5.下载安装包 二、安装部署1.创建 Edge 实例2.创建数据库3.Edge 服务安装3.1.安装服务3.2.配置 Edge3.3.运行安装脚本3.4.重新启动服务 4.访问 Edge5.故障…

html canvas怎么在图片上面加文字

在HTML canvas中&#xff0c;要让文字显示在图片上方&#xff0c;你需要按照以下步骤操作&#xff1a; 首先&#xff0c;使用drawImage()方法将图片绘制到canvas上。 然后&#xff0c;使用fillText()或strokeText()方法在canvas上绘制文本。 以下是一个简单的示例代码&#…

自动驾驶---Motion Planning之构建SLT Driving Corridor

1 背景 在上篇博客《自动驾驶---Motion Planning之Speed Boundary》中,主要介绍了Apollo中Speed Boundary的一些内容,可以构造ST图得到边界信息,最后结合粗糙的速度曲线和路径曲线,即可使用优化的方法求解得到最终的轨迹信息(s,s,s,l,l,l)。 本篇博客笔者主要介绍近…

系统重构后,对项目定制开发的兼容性问题

公司自实施产品线战略以来&#xff0c;基本推翻了全部旧有业务模块。后续以标准产品二次开发的模式进行项目开发。但在涉及到一些旧有系统二期、三期升级改造过程中。不可避免的需要解决旧有系统的客户定制化开发兼容性问题。也就是旧有系统定制开发的模块不能丢弃。重新开发从…

【SQL Server】实验八 综合设计

1 实验目的 了解和掌握数据库设计的有关理论和方法。可以灵活运用数据库设计方法设计一个中小型规模的数据库。 2 实验内容 2.1 数据库概念模型设计 进行需求分析。设计数据库概念模型&#xff0c;画出E-R图。 2.2 数据库逻辑模型设计 根据数据库概念模型设计数据库的逻…

现货大宗商品交易所软件的功能介绍有演示版

现货大宗商品交易所软件是专为大宗商品交易设计的系统平台&#xff0c;其功能涵盖了交易的各个环节&#xff0c;旨在提高交易效率、降低交易成本并促进市场规范化。以下是现货大宗商品交易所软件的主要功能&#xff1a; 用户管理模块&#xff1a; 注册与登录&#xff1a;为新…

量化系统QTYX使用攻略|“盘中战法”篇——监测个股盘口异动,机器人远程提醒(更新2.8.0)...

QTYX简介‍‍‍ 股票量化交易系统QTYX是一个即可以用于学习&#xff0c;也可以用于实战炒股分析的系统。 分享QTYX系统目的是提供给大家一个搭建量化系统的模版&#xff0c;最终帮助大家搭建属于自己的系统。因此我们提供源码&#xff0c;可以根据自己的风格二次开发。 关于QTY…

Javascript抓取京东、淘宝商品数据(商品采集商品详情图片抓取)

之前用的方法&#xff1a; let temp []var lists $(#J_goodsList li.gl-item)$.each(lists,function(idx,item){ temp.push({ id:$(item).data(sku), goods_img:$(item).find(img).attr(src), goods_name:$(item).find(.p-name em).text(), market_price:$(item).fi…

洗眼镜用什么超声波清洗机洗比较好?四款黑马产品集合力荐

对于眼镜佩戴者而言&#xff0c;保持眼镜的清洁不仅关系到舒适的佩戴体验&#xff0c;更直接影响到视觉的清晰度。然而&#xff0c;传统的清洗方法往往难以彻底去除镜片上的污渍、油脂以及细菌&#xff0c;尤其是眼镜的角落和细小缝隙&#xff0c;更是清洁的死角。随着科技的发…

HDS-NAS分配资源并挂载win和linux

1、首先创建系统文件。 选择nas存储池 2、根据自己的需求创建相应的挂载方式 3、window配置 配置成功 最后即可在window系统网络位置映射网络即可&#xff0c; 格式为\\123.3.4.5\test 注&#xff1a;IP地址 4、liunx挂载方式 创建完成之后即可挂载&#xff0c;注意目的主…

数据结构——动态顺序表

数据结构的动态顺序表有以下几个操作&#xff1a;创建&#xff0c;销毁&#xff0c;初始化&#xff0c;增删查改和打印以及内存空间不够时的扩容 本文的宏定义&#xff1a; #define SeqTypeData int 1.动态顺序表的创建 typedef struct SeqListInit{//动态顺序表的创建SeqT…

面试经典-MySQL篇

一、MySQL组成 MySQL数据库的连接池&#xff1a;由一个线程来监听一个连接上请求以及读取请求数据&#xff0c;解析出来一条我们发送过去的SQL语句SQL接口&#xff1a;负责处理接收到的SQL语句查询解析器&#xff1a;让MySQL能看懂SQL语句查询优化器&#xff1a;选择最优的查询…

springboot爱看漫画小程序的设计与实现

摘 要 相比于以前的传统手工管理方式&#xff0c;智能化的管理方式可以大幅降低爱看漫画的运营人员成本&#xff0c;实现了爱看漫画的标准化、制度化、程序化的管理&#xff0c;有效地防止了爱看漫画的随意管理&#xff0c;提高了信息的处理速度和精确度&#xff0c;能够及时、…

双指针算法_复写零

题目&#xff1a; 给一个固定长度的数组arr&#xff0c;将数组中出现的每一个0都复写一遍&#xff0c;并且将其余元素都往右移动 且不要再超过数组长度的位置写入元素&#xff0c;在数组上直接修改 示例&#xff1a; 双数组模拟操作&#xff1a; 从示例来看&#xff0c;因为…

《Learning Hierarchical Modular Networks for Video Captioning》论文笔记

论文信息 原文链接&#xff1a; Learning Hierarchical Modular Networks for Video Captioning | IEEE Journals & Magazine | IEEE Xplore 原文代码 GitHub - MarcusNerva/HMN: [CVPR2022] Official code for Hierarchical Modular Network for Video Captioning. Ou…

GPT3.5、GPT4及Midjourney中转接口ChatGPT系统KEY使用方法

很多使用ChatGPT系统、还有SparkAi、NineAi等系统都存在个比较烦的问题&#xff0c;Openai API 3.5KEY 4.0KEY&#xff0c;Midjourney接口KEY都没有一个稳定的购买或者使用渠道。直连KEY买来还得得建立反代主机&#xff0c;Midjourney接口通过MJ-PROXY-PLUS系统折腾了几天也能使…

linux用git拉取我云端以及git处理冲突

拉取后切换一个跟云端分支(dev)一样的 git branch --set-upstream-toorigin/dev dev 之后就同步了 A在dev分支写了iii,提交 B在dev分支写了hhh,提交,冲突 怎么修改,B把云端的拉下来,随便改改就行

大语言模型RAG-技术概览 (一)

大语言模型RAG-技术概览 (一) 一 RAG概览 检索增强生成&#xff08;Retrieval-AugmentedGeneration, RAG&#xff09;。即大模型在回答问题或生成问题时会先从大量的文档中检索相关的信息&#xff0c;然后基于这些信息进行回答。RAG很好的弥补了传统搜索方法和大模型两类技术…