C++:类与对象(三)

目录

再谈构造函数 

构造函数体赋值

初始化列表

explicit关键字

static成员

友元

友元函数

友元类

内部类

再次理解封装


再谈构造函数 

首先要明白声明、定义、初始化三个概念的不同。

声明:指定变量的名字和类型,可以多次声明。

定义:为该成员变量分配存储空间,有且仅有一个定义。

初始化:为该成员变量赋初值。

在类的声明中,静态成员变量仅完成了声明过程,并没有进行定义和赋初值。

静态成员变量在编译时存储在静态存储区,即定义过程应该在编译时完成,因此一定要在类外进行定义,但可以不初始化。

构造函数体赋值

在创建对象时,编译器通过调用构造函数,给对象中各个成员变量一个合适的初始值。


class Date
{
public:Date(int year, int month, int day){_year = year;_month = month;_day = day;}private:int _year;int _month;int _day;
};

虽然上述构造函数调用之后,对象中已经有了一个初始值,但是不能将其称作为类对象成员的初始化,构造函数体中的语句只能将其称作为赋初值,而不能称作初始化。因为初始化只能初始化一次,而构造函数体内可以多次赋值


初始化列表

初始化列表语法格式:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟一个放在括号中的初始值或表达式。


class Date
{
public:Date(int year, int month, int day): _year(year), _month(month), _day(day){}private:int _year;int _month;int _day;
};

需要注意每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次)

类中包含以下成员,必须放在初始化劣币位置初始化:

  • 引用成员变量
  • const成员变量
  • 子应用类型成员(且该成员类没有默认构造函数时)
class A
{
public:A(int a):_a(a){}
private:int _a;
};
class B
{
public:B(int a, int ref):_aobj(a),_ref(ref),_n(10){}
private:A _aobj; // 没有默认构造函数int& _ref; // 引用const int _n; // const 
};

尽量使用初始化劣币初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量,一定会先试用初始化劣币初始化。

class Time
{
public:Time(int hour = 0):_hour(hour){cout << "Time()" << endl;}
private:int _hour;
};class Date
{
public:Date(int day){}
private:int _day;Time _t;
};int main()
{Date d(1);
}

成员变量在类中声明次序就是其在初始化劣币中的初始化顺序,与其初始化列表中的先后次序无关。

class A
{
public:A(int a):_a1(a),_a2(_a1){}void Print() {cout<<_a1<<" "<<_a2<<endl;}
private:int _a2;int _a1;
};
int main() {A aa(1);aa.Print();
}


explicit关键字

class Date
{public:Date(int year) :_year(year){cout<<"Date(int year)" << endl;}Date(const Date& date){cout << "Date(const Date& date)" << endl;}
private:int _year;   //声明};
int main()
{Date d(2022);Date d2 = 2022; //隐式类型转换}

这段代码就是隐式类型转换,因为 i 和 j 相近类型,意义相似,他们都是表示数据大小,所以可以将  i 赋值给 j ,隐式类型转换还会产生一个临时变量,而下面这段代码发生的就是强制类型转换

int* p = &j;
int d = (int)p;

因为他俩一个表示地址,一个表示大小,不发生隐式类型转换,但是可通过强制类型转换。

而此刻这个日期类也发生了隐式类型转换,本来整形和日期类没有任何关系,但是我们写的类支持一个单参数的构造函数后,整形就可以构造一个日期类的对象。
本来是用2022构造一个临时对象Date(2022),再用这个对象拷贝构造d2,但是C++编译器在连续的一个过程中,多个构造会被优化,合二为一,所以这里被优化为直接构造。注意:虽然他俩都是直接构造但是他俩的意义是不一样的。


我们可以用explicit修饰构造函数,将会禁止单参构造函数的隐式转换。 

class Date
{
public://不想让这个过程发生就加这个关键字explicit Date(int year) :_year(year){cout << "Date(int year)" << endl;}Date(const Date& date){cout << "Date(const Date& date)" << endl;}
private:int _year;   //声明};

static成员

static静态的。此时申请的内存区域在数据段(静态区)。生命周期也就可程序一致。

静态成员:

        如果是静态成员,那么,在初始化列表无法进行初始化,只能在类外进行初始化。但是由于C++语法特性,在static前加上const即就可以直接在类里进行初始化了,就无需在类外进行。静态成员属于此类,该类的所有对象均可以使用。

静态函数:

        在成员函数前加上static就是静态函数。此时就不会默认给this指针了。既然没有this指针就无法访问成员变量,只能访问静态成员。而且此时静态函数也可以不用通过对象去调用,直接前面加上类域即可

实现一个类,计算程序中创建出了多少个类对象,如果想要字节数会很难数,因为编译器会员优化的场景,所以通过程序解决

int _count = 0;
class A
{
public:A(int a = 0){_count++;}A(const A& a){_count++;}private:int _a;
};void f(A a)
{
}int main()
{A a1;A a2 = 1;f(a1);cout << _count << endl;
}

这是已经实现好的,但是会有很多缺点,_count是全局变量,会被随意修改,

如果我们将他定义为成员变量呢? 也是不行的,因为这样的话,_count就成了每个对象都有的成员起不到计数的作用。

class A
{
public:A(int a = 0){_Scount++;}A(const A& a){_Scount++;}private:int _a;//静态成员变量属于整个类,所有对象,生命周期在整个程序运行期间static int _Scount; //声明
};
int A::_Scount = 0;  //定义初始化

在成员变量前加static就可以把他定义成静态成员变量了。静态成员变量属于整个类,所有对象,生命周期在整个程序运行期间。在类型外面定义的时候,要指定它是属于这个类。


友元

友元函数

正所谓friend,即友好关系,适用于函数和类。

友元函数:

此函数可以访问此类中的所有成员。

声明方式:在类中使用friend加在此函数前进行声明即可。

首先,我们来填上上面在用流提取流插入重载的坑,因为需要cin、cout作为第一个参数,所以需要定义成全局函数,但是为了能够访问类中的成员,所以此时在日期类里声明为友元函数即可:

class Date
{//一般友元关系声明在第一行:friend inline ostream& operator<<(ostream& out, const Date& d);friend inline istream& operator>>(istream& in, Date& d);//......
}
//声明为内联 -- 节省栈帧
inline ostream& operator<<(ostream& out, const Date& d)
{out << d._year << '/' << d._month << '/' << d._day << endl;return out;
}inline istream& operator>>(istream& in, Date& d)
{in >> d._year >> d._month >> d._day;return in;
}

友元类

友元类:

此时这个类可以访问声明友元的类里的所有成员。但是注意友元关系是单向的,即声明友元的类就不可访问对应的这类里面的私有、保护成员。

class Test1
{friend class Test2;//友元类int _num;
public:Test1(int num = 0):_num(num){}
};
class Test2
{Test1 t;
public:void Print(){cout << t._num << endl;}
};int main()
{Test2 t;t.Print();return 0;
}

此处友元类就可以访问声明友元的类的所有成员了,当然,友元是单向的关系,不可以反过来进行访问。


内部类

概念:如果一个类定义在另一个类的内部,这个内部类就叫做内部类。注意此时这个内部类是一个独立的 类,它不属于外部类,更不能通过外部类的对象去调用内部类。外部类对内部类没有任何优越的访问权限。
注意:内部类就是外部类的友元类。注意友元类的定义,内部类可以通过外部类的对象参数来访问外部类中的所有成员。但是外部类不是内部类的友元。

  • 特性:
  • 1. 内部类可以定义在外部类的public、protected、private都是可以的。
  • 2. 注意内部类可以直接访问外部类中的static、枚举成员,不需要外部类的对象/类名。
  • 3. sizeof(外部类)=外部类,和内部类没有任何关系。
class A
{
private:static int k;int h;
public:class B // B天生就是A的友元{public:void foo(const A& a){cout << k << endl;//OKcout << a.h << endl;//OK}};
};int A::k = 1;int main()
{A::B b;b.foo(A());return 0;
}

再次理解封装

现实生活中的实体计算机并不认识,计算机只认识二进制格式的数据。如果想要让计算机认识现实生活中的实体,用户必须通过某种面向对象的语言,对实体进行描述,然后通过编写程序,创建对象后计算机才可以认识。比如想要让计算机认识洗衣机,就需要:

  1. 用户先要对现实中洗衣机实体进行抽象—即在人为思想层面对洗衣机进行认识,洗衣机有什么属性,有那些功能,即对洗衣机进行抽象认知的一个过程
  2. 经过1之后,在人的头脑中已经对洗衣机有了一个清醒的认识,只不过此时计算机还不清楚,想要让计算机识别人想象中的洗衣机,就需要人通过某种面相对象的语言(比如:C++、Java、Python等)将洗衣机用类来进行描述,并输入到计算机中
  3. 经过2之后,在计算机中就有了一个洗衣机类,但是洗衣机类只是站在计算机的角度对洗衣机对象进行描述的,通过洗衣机类,可以实例化出一个个具体的洗衣机对象,此时计算机才能知道洗衣机是什么东西。
  4. 用户就可以借助计算机中洗衣机对象,来模拟现实中的洗衣机实体了

在类和对象阶段,一定要体会到,类是对某一类实体(对象)来进行描述的,描述该对象具有那些属性,那些方法,描述完成后就形成了一种新的自定义类型,才用该自定义类型就可以实例化具体的对象

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

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

相关文章

c++ 指针总结

概述 内存地址 在计算机内存中&#xff0c;每个存储单元都有一个唯一的地址(内存编号)。通俗理解&#xff0c;内存就是房间&#xff0c;地址就是门牌号 指针和指针变量 指针&#xff08;Pointer&#xff09;是一种特殊的变量类型&#xff0c;它用于存储内存地址。指针的实质…

【Python】面向对象(专版提升2)

面向对象 1. 概述1.1面向过程1.2 面向对象 2. 类和对象2.1 语法2.1.1 定义类2.1.2 实例化对象 2.2 实例成员2.2.1 实例变量2.2.2 实例方法2.2.3 跨类调用 3. 三大特征3.1 封装3.1.1 数据角度3.1.2 行为角度3.1.3 案例:信息管理系统3.1.3.1 需求3.1.3.2 分析3.1.3.3 设计 3.2 继…

有关格式输入输出的问题

对于格式输入输出问题&#xff0c;我们最好用c语言编写代码&#xff01;&#xff01;&#xff01; 成绩统计 难点&#xff1a;格式化输出 #include <cstdio> using namespace std; typedef long long ll;ll n,score,a,b;int main() {//及格>60 优秀>85 求及格率…

javaEE初阶——多线程(四)

T04BF &#x1f44b;专栏: 算法|JAVA|MySQL|C语言 &#x1faf5; 小比特 大梦想 此篇文章与大家分享多线程专题的第四篇(关于多线程代码案例中的单例模式) 如果有不足的或者错误的请您指出! 目录 九、多线程代码案例(单例模式)1.单例模式1.1饿汉模式1.2懒汉模式1.3使用场景1.4上…

【刷题】图论——最小生成树:Prim、Kruskal【模板】

假设有n个点m条边。 Prim适用于邻接矩阵存的稠密图&#xff0c;时间复杂度是 O ( n 2 ) O(n^2) O(n2)&#xff0c;可用堆优化成 O ( n l o g n ) O(nlogn) O(nlogn)。 Kruskal适用于稀疏图&#xff0c;n个点m条边&#xff0c;时间复杂度是 m l o g ( m ) mlog(m) mlog(m)。 Pr…

华媒舍:7种方式,打造出旅游媒体套餐

现如今&#xff0c;伴随着旅游业发展与繁荣&#xff0c;更多旅游业发展从业人员越来越重视产品营销品牌基本建设&#xff0c;希望可以将自己的度假旅游产品和服务营销推广给更多的潜在用户。而建立一个优秀的旅游业发展媒体套餐内容品牌是吸引目标客户的重要步骤。下面我们就详…

streamlit 大模型前段界面

结合 langchain 一起使用的工具&#xff0c;可以显示 web 界面 pip install streamlit duckduckgo-search 运行命令 streamlit run D:\Python_project\NLP\大模型学习\test.py import os from dotenv import load_dotenv from langchain_community.llms import Tongyi load…

Flutter仿Boss-6.底部tab切换

效果 实现 图片资源采用boss包中的动画webp资源。Flutter采用Image加载webp动画。 遇到的问题 问题&#xff1a;Flutter加载webp再次加载无法再次播放动画问题 看如下代码&#xff1a; Image.asset(assets/images/xxx.webp,width: 40.w,height: 30.w, )运行的效果&#xf…

图片过大怎么改小?图片尺寸在线修改的方法

在通过电子邮件或即时消息传递应用程序发送图片时&#xff0c;某些平台上传图片的时候经常遇到尺寸不符合的情况&#xff0c;通过在线修改图片尺寸&#xff0c;您可以调整图片的大小&#xff0c;以满足限制要求&#xff0c;并确保图片可以顺利地通过电子邮件或消息传递应用程序…

HarmonyOS4 页面路由

Index.ets: import router from ohos.routerclass RouterInfo {// 页面路径url: string// 页面标题title: stringconstructor(url: string, title: string) {this.url urlthis.title title} }Entry // 入口組件 Component struct Index {State message: string 页面列表// …

Selenium+Chrome Driver 爬取搜狐页面信息

进行selenium包和chromedriver驱动的安装 安装selenium包 在命令行或者anaconda prompt 中输入 pip install Selenium 安装 chromedriver 先查看chrome浏览器的版本 这里是 123.0.6312.106 版 然后在http://npm.taobao.org/mirrors/chromedriver/或者https://googlechrom…

【深度学习实战(2)】如何使用matplotlib.pyplot模块记录自己的训练,验证损失

一、matplotlib库 在我们自己训练模型时&#xff0c;常常会使用matplotlib库来绘制oss和accuracy的曲线图&#xff0c;帮助我们分析模型的训练表现。 matplotlib库安装&#xff1a;pip install matplotlib 二、代码 import matplotlib.pyplot as plt import torch import to…

2024年蓝桥杯40天打卡总结

2024蓝桥杯40天打卡总结 真题题解其它预估考点重点复习考点时间复杂度前缀和二分的两个模板字符串相关 String和StringBuilderArrayList HashSet HashMap相关蓝桥杯Java常用算法大数类BigInteger的存储与运算日期相关考点及函数质数最小公倍数和最大公约数排序库的使用栈Math类…

Redis系列之基于Linux单机安装

Redis 是一个开源的使用 ANSI C 语言编写、遵守 BSD 协议、支持网络、可基于内存、分布式、可选持久性的键值对(Key-Value)存储数据库&#xff0c;并提供多种语言的 API。最近学习需要用到Redis&#xff0c;所以就去Linux服务器上部署一个&#xff0c;做下记录&#xff0c;方便…

【网站项目】数学辅导微信小程序

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

Ollama、FastGPT大模型RAG结合使用案例

参考: https://ollama.com/download/linux https://doc.fastai.site/docs/intro/ https://blog.csdn.net/m0_71142057/article/details/136738997 https://doc.fastgpt.run/docs/development/custom-models/m3e/ Ollama作为后端大模型加载运行 FastGPT作为前端页面聊天集成RA…

『FPGA通信接口』汇总目录

Welcome 大家好&#xff0c;欢迎来到瑾芳玉洁的博客&#xff01; &#x1f611;励志开源分享诗和代码&#xff0c;三餐却无汤&#xff0c;顿顿都被噎。 &#x1f62d;有幸结识那个值得被认真、被珍惜、被捧在手掌心的女孩&#xff0c;不出意外被敷衍、被唾弃、被埋在了垃圾堆。…

【IR-SDE】Image Restoration SDE项目演示运行app.py

背景&#xff1a; code:GitHub - Algolzw/image-restoration-sde: Image Restoration with Mean-Reverting Stochastic Differential Equations, ICML 2023. Winning solution of the NTIRE 2023 Image Shadow Removal Challenge. paper: Official PyTorch Implementations o…

ppt技巧:如何将Word文档大纲中导入到幻灯片中?

在PowerPoint中&#xff0c;将Word文档的大纲导入到新的幻灯片是一种非常实用的技巧。以下是详细的步骤&#xff1a; 首先&#xff0c;需要打开PowerPoint软件并打开原始的幻灯片文件。 在PowerPoint的顶部【开始】菜单栏中&#xff0c;找到并点击“新建幻灯片”按钮&#xff0…

最新常见的图数据库对比,选型,架构,性能对比

图数据库排名 地址&#xff1a;https://db-engines.com/en/ranking/graphdbms 知识图谱查询语言 SPARQL、Cypher、Gremlin、PGQL 和 G-CORE 语法 / 语义 / 特性SPARQLCypherGremlinPGQLG-CORE图模式匹配查询语法CGPCGPCGP(无可选)1CGPCGP语义子图同态、包 2无重复边、包 2子…