类和对象深入理解

目录

  • static成员
    • 概念
      • 静态成员变量
        • 面试题
        • 补充
          • 代码1
          • 代码2
          • 代码3
          • 如何访问private中的成员变量
      • 静态成员函数
        • 静态成员函数没有this指针
    • 特性
  • 友元
    • 友元函数
    • 友元类
  • 内部类
    • 特性1
    • 特性2
  • 匿名对象
  • 拷贝对象时的一些编译器优化

感谢各位大佬对我的支持,如果我的文章对你有用,欢迎点击以下链接
🐒🐒🐒 个人主页
🥸🥸🥸 C语言
🐿️🐿️🐿️ C语言例题
🐣🐣🐣 python
🐓🐓🐓 数据结构C语言
🐔🐔🐔 C++
🐿️🐿️🐿️ 文章链接目录

static成员

概念

声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量
用static修饰的成员函数,称之为静态成员函数。
静态成员变量一定要在类外进行初始化

静态成员变量

面试题

面试题:实现一个类,计算程序中创建出了多少个类对象。

class A
{
public:A(){++n;}A(const A& aa){++ n;}
private:static int n;
}; 
int A::n = 0;

这里的n就是一个静态全局变量,注意静态变量是不能给缺省值的,因为他不是单独属于某一个对象,而是属于这个类的所有对象,因此需要在类外面定义

由于n受域作用限定符的限制,当我们屏蔽掉private后就可以访问n了
在这里插入图片描述

我们再来看看下面的三段代码

补充
代码1
class A
{
public:A(){++n;}A(const A& aa){++ n;}
//private:static int n;
}; 
int A::n = 0;
int main()
{A aa1;A aa2;A* ptr = nullptr;cout << aa1.n << endl;cout << aa2.n << endl;cout << ptr->n << endl;return

在这里插入图片描述

代码2
class A
{
public:A(){++n;}A(const A& aa){++ n;}
//private:static int n;
}; 
int A::n = 0;
int main()
{A aa1;//A aa2;A* ptr = nullptr;cout << aa1.n << endl;//cout << aa2.n << endl;cout << ptr->n << endl;return 0;
}

在这里插入图片描述

代码3
class A
{
public:A(){++n;}A(const A& aa){++ n;}
//private:static int n;
}; 
int A::n = 0;
int main()
{//A aa1;//A aa2;A* ptr = nullptr;//cout << aa1.n << endl;//cout << aa2.n << endl;cout << ptr->n << endl;return 0;
}

在这里插入图片描述
上面的三个代码中ptr输出的n的值是不一样的,这需要我们了解static存储的变量在静态区
比如ptr->n,n并不在ptr指向的对象里,而是在静态区,在寻找n的时候就是去静态区里找
因为是受到static修饰,所以n的值是全局变量,全局变量不想局部变量,出了作用域后就会销毁然后从新开始,也就是说这里的n不会因为一个对象结束后就重新变成0

如何访问private中的成员变量

上面的代码中我们都是将private屏蔽掉才可以访问到n的,当private没有屏蔽的时候,就会因为权限导出不允许访问
在这里插入图片描述
要想解决这个问题只有在公有区域里创建一个函数Getn()去获得n的值

class A
{
public:A(){++n;}A(const A& aa){++ n;}int Getn(){return n;}
private:static int n;
}; 
int A::n = 0;
int main()
{A aa1;cout << aa1.Getn() << endl;return 0;
}

在这里插入图片描述

静态成员函数

静态成员函数的访问方式如下
在这里插入图片描述
A::Getn()也是可以这样访问的,另外静态成员变量也同理
在这里插入图片描述

静态成员函数没有this指针

静态成员函数与普通的成员函数不同点在于静态成员函数没有this指针,所以不能访问非静态成员变量或者函数

class A
{
public:A(){++n;}A(const A& aa){++ n;}static int Getn(){a++;return n;}
private:static int n;int a;
}; 
int A::n = 0;
int main()
{A aa1;cout << A::n << endl;return 0;
}

在这里插入图片描述

特性

1. 静态成员为所有类对象所共享,不属于某个具体的对象,存放在静态区
2. 静态成员变量必须在类外定义,定义时不添加static关键字,类中只是声明
3. 类静态成员即可用 类名::静态成员 或者 对象.静态成员 来访问
4. 静态成员函数没有隐藏的this指针,不能访问任何非静态成员
5. 静态成员也是类的成员,受public、protected、private 访问限定符的限制

友元

友元提供了一种突破封装的方式,有时提供了便利。但是友元会增加耦合度,破坏了封装,所以
友元不宜多用。所以友元我们了解一下就行了
友元分为:友元函数和友元类

友元函数

问题:
现在尝试去重载operator<<,然后发现没办法将operator<<重载成成员函数
因为cout的输出流对象和隐含的this指针在抢占第一个参数的位置。this指针默认是第一个参数也就是左操作数了。
但是实际使用中cout需要是第一个形参对象,才能正常使用
所以要将operator<<重载成全局函数。但又会导致类外没办法访问成员,此时就需要友元来解决。operator>>同理。

class Date
{
public:Date(int year, int month, int day): _year(year), _month(month), _day(day){}// d1 << cout; -> d1.operator<<(&d1, cout); 不符合常规调用// 因为成员函数第一个参数一定是隐藏的this,所以d1必须放在<<的左侧ostream& operator<<(ostream& _cout){_cout << _year << "-" << _month << "-" << _day << endl;return _cout;}
private:int _year;int _month;int _day;
};

友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在
类的内部声明,声明时需要加friend关键字。

class Date
{friend ostream& operator<<(ostream& _cout, const Date& d);friend istream& operator>>(istream& _cin, Date& d);
public:Date(int year = 1900, int month = 1, int day = 1): _year(year), _month(month), _day(day){}
private:int _year;int _month;int _day;
};
ostream& operator<<(ostream& _cout, const Date& d)
{_cout << d._year << "-" << d._month << "-" << d._day;return _cout; 
}
istream& operator>>(istream& _cin, Date& d)
{_cin >> d._year;_cin >> d._month;_cin >> d._day;return _cin;
}
int main()
{Date d;cin >> d;cout << d << endl;return 0;
}

说明:
友元函数可访问类的私有和保护成员,但不是类的成员函数
友元函数不能用const修饰(没有this指针)
友元函数可以在类定义的任何地方声明,不受类访问限定符限制
一个函数可以是多个类的友元函数
友元函数的调用与普通函数的调用原理相同

友元类

友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。
友元关系是单向的,不具有交换性。
比如上述Time类和Date类,在Time类中声明Date类为其友元类,那么可以在Date类中直接
访问Time类的私有成员变量,但想在Time类中访问Date类中私有的成员变量则不行。
友元关系不能传递
如果C是B的友元, B是A的友元,则不能说明C时A的友元。友元关系不能继承

class Time
{friend class Date;   // 声明日期类为时间类的友元类,则在日期类中就直接访问Time类
中的私有成员变量
public:Time(int hour = 0, int minute = 0, int second = 0): _hour(hour), _minute(minute), _second(second){}private:int _hour;int _minute;int _second;
};
class Date
{
public:Date(int year = 1900, int month = 1, int day = 1): _year(year), _month(month), _day(day){}void SetTimeOfDate(int hour, int minute, int second){// 直接访问时间类私有的成员变量_t._hour = hour;_t._minute = minute;_t._second = second;}private:int _year;int _month;int _day;Time _t;
};

内部类

概念:如果一个类定义在另一个类的内部,这个内部类就叫做内部类。内部类是一个独立的类,
它不属于外部类,更不能通过外部类的对象去访问内部类的成员。外部类对内部类没有任何优越
的访问权限。

注意:内部类就是外部类的友元类,内部类可以通过外部类的对象参数来访问外部类中的所有成员
但是外部类不是内部类的友元。

特性:
1. sizeof(外部类)=外部类,和内部类没有任何关系。
2. 内部类可以定义在外部类的public、protected、private都是可以的,且内部类受类域限制
3. 注意内部类可以直接访问外部类中的static成员,不需要外部类的对象/类名(内部类是外部类的友元类)

特性1

class A
{
private:static int k;int h;
public:class B // B天生就是A的友元{public:void foo(const A& a){cout << k << endl;cout << a.h << endl;}};
};
int A::k = 1;
int main()
{A::B b;b.foo(A());cout << sizeof(A) << endl;return 0;
}

在这里插入图片描述

sizeof(A)的结果是4,可能很多人会觉得B在A里面的,所以sizeof(A)的结果是包含了B的空间的,但是事实上不是这样的,如果要让sizeof(A)的结果是算上B的空间大小的话应该像下面这段代码这样写

class B
{
private:int _b1;
};
class A
{
private:static int k;int h;B _b;
}

此外类是不占用空间的,因为类只是一个声明,而在定义的时候才会有空间,也就是说声明只是说有这么一个东西,但是不会讲空间分配给他,而定义则是让这个东西真实的存在,并分配空间给他

特性2

内部类也是受访问限定符和类域的限制

class A
{
public:class B{};
};
int main()
{A a;B b;return 0;
}

在这里插入图片描述
当我们用域作用限定符的时候就可以正常运行

class A
{
public:class B{};
};
int main()
{A a;A::B b;return 0;
}

在这里插入图片描述
但是当class B 在A的private中就会因为B是私有导致无法访问

class A
{
private:class B{};
};
int main()
{A a;A::B b;return 0;
}

在这里插入图片描述

匿名对象

匿名对象就是没有名字的对象,他的特点是生命周期只在当前一行

class A
{
public:A(int a = 0):_a(a){cout << "A(int a)" <<a<< endl;}~A(){cout << "~A()" << endl;}
private:int _a;
};
int main()
{A aa1;A aa2(2);A();A(3);return 0;
}

在这里插入图片描述

拷贝对象时的一些编译器优化

在传参和传返回值的过程中,一般编译器会做一些优化,减少对象的拷贝,这个在一些场景下还
是非常有用的。
但是不同的编译器优化程度是不同的,所以我们只需要简单了解一下就可以了

class A
{
public:A(int a = 0):_a(a){cout << "A(int a)" << endl;}A(const A& aa):_a(aa._a){cout << "A(const A& aa)" << endl;}A& operator=(const A& aa){cout << "A& operator=(const A& aa)" << endl;if (this != &aa){_a = aa._a;}return *this;}~A(){cout << "~A()" << endl;}
private:int _a;
};
void f1(A aa)
{}
A f2()
{A aa;return aa;
}
int main()
{// 传值传参A aa1;f1(aa1);cout << endl;// 传值返回f2();cout << endl;// 隐式类型,连续构造+拷贝构造->优化为直接构造f1(1);// 一个表达式中,连续构造+拷贝构造->优化为一个构造f1(A(2));cout << endl;// 一个表达式中,连续拷贝构造+拷贝构造->优化一个拷贝构造A aa2 = f2();cout << endl;// 一个表达式中,连续拷贝构造+赋值重载->无法优化aa1 = f2();cout << endl;return 0;
}

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

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

相关文章

Linux-DNS

DNS域名解析服务 1.DNS介绍 DNS 是域名系统 (Domain Name System) 的缩写&#xff0c;是因特网的一项核心服务&#xff0c;它作为可以将域名和IP地址相互映射的一个分布式数据库&#xff0c;能够使人更方便的访问互联网&#xff0c;而不用去记住能够被机器直接读取的IP数串。…

大气热力学(2)——热力学基础

本篇文章源自我在 2021 年暑假自学大气物理相关知识时手写的笔记&#xff0c;现转化为电子版本以作存档。相较于手写笔记&#xff0c;电子版的部分内容有补充和修改。笔记内容大部分为公式的推导过程。 文章目录 2.0 本文所用符号一览2.1 准静态过程2.2 热量和热容量2.2.1 热量…

Java对象

面向对象和面向过程的区别 两者的主要区别在于解决问题的方式不同 面向过程把解决问题的过程拆成一个个方法&#xff0c;通过一个个方法的执行解决问题。 面向对象会先抽象出对象&#xff0c;然后用对象执行方法的方式解决问题。 另外&#xff0c;面向对象开发的程序一般更易维…

乞丐传武功

题目 你施舍给了路边的乞丐两个馒头&#xff0c;谁料这个乞丐其实是隐士高人。为了回报你的善心&#xff0c;只见他缓缓从怀中掏出了数本武功秘籍&#xff0c;让你从中挑选一本。你珍重地接过这些秘籍&#xff0c;目光扫过每本封面&#xff0c;降龙十八掌、神照经、易筋经、凌…

[FreeRTOS 基础知识] 互斥量 概念

文章目录 基础知识互斥量互斥量与信号量区别优先级反转优先级继承小结 基础知识 [FreeRTOS 基础知识] 信号量 概念 互斥量 互斥量&#xff08;Mutex&#xff0c;全称&#xff1a;Mutual Exclusion&#xff09;&#xff0c;在计算机科学中&#xff0c;是一种用于防止多个进程同…

科研绘图系列:R语言实验结果组图(linechart + barplot)

介绍 实验结果的多样性意味着每个结果都可能揭示研究的不同方面或角度。在科学研究和数据分析中,通常我们会收集一系列数据点,每个数据点都对应着实验的一个特定变量或条件。为了全面理解这些数据,我们可能会采用多种可视化技术来展示它们。 将多个结果分别可视化,可以让…

亲子时光里的打脸高手,贾乃亮与甜馨的父爱如山

贾乃亮这波操作&#xff0c;简直是“实力打脸”界的MVP啊&#xff01; 7月5号&#xff0c;他一甩手&#xff0c;甩出张合照&#xff0c; 瞬间让多少猜测纷飞的小伙伴直呼&#xff1a;“脸疼不&#xff1f;”带着咱家小甜心甜馨&#xff0c; 回了哈尔滨老家&#xff0c;这趟亲…

Nginx(http配置、https配置)访问Spring Boot 项目

前文 记录一下在linux服务器下配置nginx中nginx.conf文件代理访问springboot项目 1. spring boot.yml配置 其他mysql,redis,mybatis等之类的配置就不一一列出了 # 自定义配置 为了等下验证读取的配置文件环境 appName: productserver:port: 8083 # 应用服务 WEB 访问端口s…

SQL窗口函数详解

详细说明在sql中窗口函数是什么&#xff0c;为什么需要窗口函数&#xff0c;有普通的聚合函数了那窗口函数的意义在哪&#xff0c;窗口函数的执行逻辑是什么&#xff0c;over中的字句是如何使用和理解的&#xff08;是不是句句戳到你的痛点&#xff0c;哼哼&#xff5e;&#x…

C语言编译和编译预处理

编译预处理 • 编译是指把高级语言编写的源程序翻译成计算机可识别的二进制程序&#xff08;目标程序&#xff09;的过程&#xff0c;它由编译程序完成。 • 编译预处理是指在编译之前所作的处理工作&#xff0c;它由编译预处理程序完成 在对一个源程序进行编译时&#xff0c;…

全国青少年软件编程等级考试-四级-奇偶之和(真题)

题目&#xff1a;奇偶之和 1.准备工作 (1)保留舞台中的小猫角色&#xff1b; 2.功能实现 (1)分别计算1&#xff5e;100中&#xff0c;奇数之和&#xff0c;偶数之和&#xff1b; (2)说出奇数之和&#xff0c;偶数之和。 讲解&#xff1a; 1、如何判断奇偶数 奇数是指除以2有…

C++deque容器

文章目录 deque容器概念deque操作deque对象的带参数构造deque头部和末尾的添加移除操作deque的数据存取deque与迭代器deque赋值deque插入deque删除 deque容器概念 deque是双端数组&#xff0c;而vector是单端的。 deque头部和尾部添加或移除元素都非常快速, 但是在中部安插元…

在x86/amd64的机器上使用Docker运行arm64v8/ubuntu并安装ROS1

一、准备工作 主要是因为国内网络的问题&#xff0c;可能导致镜像拉取失败&#xff0c;解决办法参考&#xff1a;镜像加速 二、安装运行过程 2.1拉取镜像&#xff1a; sudo docker pull arm64v8/ubuntu:20.04这个是ubuntu的拉取指令&#xff0c;其他的也是类似。 2.2 运行…

【DevOps】运维过程中经常遇到的Http错误码问题分析(一)

一、解决HTTP 408错误&#xff1a;上传3M文件时请求超时的问题 在开发Web应用程序时&#xff0c;遇到HTTP 408状态码&#xff08;请求超时&#xff09;是常见的问题。特别是在上传大文件时&#xff0c;这种情况更容易发生。本文将探讨在上传一个3M文件时&#xff0c;Web服务器…

LeetCode题练习与总结:排序链表--148

一、题目描述 给你链表的头结点 head &#xff0c;请将其按 升序 排列并返回 排序后的链表 。 示例 1&#xff1a; 输入&#xff1a;head [4,2,1,3] 输出&#xff1a;[1,2,3,4]示例 2&#xff1a; 输入&#xff1a;head [-1,5,3,4,0] 输出&#xff1a;[-1,0,3,4,5]示例 3&am…

封锁-封锁模式(共享锁、排他锁)、封锁协议(两阶段封锁协议)

一、引言 1、封锁技术是目前大多数商用DBMS采用的并发控制技术&#xff0c;封锁技术通过在数据库对象上维护锁来实现并发事务非串行调度的冲突可串行化 2、基于锁的并发控制的基本思想是&#xff1a; 当一个事务对需要访问的数据库对象&#xff0c;例如关系、元组等进行操作…

【嵌入式开发 Linux 常用命令系列 1.6 -- grep 过滤指定的目录】

请阅读【嵌入式开发学习必备专栏 】 文章目录 grep 过滤指定目录 grep 过滤指定目录 在Linux中使用grep搜索字符串并希望排除特定目录时&#xff0c;可以使用--exclude-dir参数。这个参数允许你指定一个或多个目录名称来排除它们的内容不被grep搜索。这对于忽略一些常见的临时…

LLM - 词向量 Word2vec

1. 词向量是一个词的低维表示&#xff0c;词向量可以反应语言的一些规律&#xff0c;词意相近的词向量之间近乎于平行。 2. 词向量的实现&#xff1a; &#xff08;1&#xff09;首先使用滑动窗口来构造数据&#xff0c;一个滑动窗口是指在一段文本中连续出现的几个单词&#x…

llamaindex实战-使用本地大模型和数据库对话

概述 本文使用NLSQLTableQueryEngine 查询引擎来构建SQL的自然语言处理查询。 请注意&#xff0c;我们需要指定要与该查询引擎一起使用的表。如果我们不这样做&#xff0c;查询引擎将提取所有架构上下文&#xff0c;这可能会溢出 LLM 的上下文窗口。 在以下情况都可以使用NL…

如何用Java写一个整理Java方法调用关系网络的程序

大家好&#xff0c;我是猿码叔叔&#xff0c;一位 Java 语言工作者&#xff0c;也是一位算法学习刚入门的小学生。很久没有为大家带来干货了。 最近遇到了一个问题&#xff0c;大致是这样的&#xff1a;如果给你一个 java 方法&#xff0c;如何找到有哪些菜单在使用。我的第一想…