【C++】匿名对象 | explicit | static静态成员 | 友元

news2024/11/24 12:55:32

匿名对象

有些情况下,我们创建变量只是临时用一用,以后不会再用到了。这时,如果创建变量还要起名字,是不是很多余?

对此,C++引入了 匿名对象 供临时使用。

例如:如果我们创建对象slt,仅仅是为了调用一次Sum_Solution(),那不如用匿名对象。

匿名对象:指在没有被命名的情况下创建的临时对象。

格式:类名( )

说明:

1.匿名对象的生命周期只在本行。也就是说,一旦语句执行完,会调用匿名对象的析构函数,销毁它。

不信我们来验证下,看看是不是执行完立马销毁:

class Date
{
public:
    Date(int year)
        :_year(year)
    {
        cout << "Date()" << endl;
    }
    ~Date()
    {
        cout << "~Date()" << endl;
    }
private:
    int _year;
};
int main()
{
    Date (2000);
    Date d1(1000);
    Date d2(1000);
    Date d3(1000);
​
    return 0;
}

结果:

补:

创建匿名对象后,编译器可能会报警告,这是正常的。

explicit关键字

作用:explicit修饰构造函数,可以禁止类型转换。

在进一步讲解explicit之前,我们先来回顾一下:什么是类型转换?

想一想,Date d1=2022,我们是不是把一个int类型的值赋给一个Date类型的对象?

能够赋值成功,是因为其间默默进行了类型的转换。

细究来说,这两种创建对象的方式是不一样的:

Date d1(2022);   //直接调用构造函数
​
Date d2 = 2022;   //本质是一步(隐式)类型转换:2022从int类型转成Date类型

第二种方式可以视为3步:先构造,再拷贝构造,然后编译器优化,最终结果才是调用了构造函数。

2022先构造出一个临时对象(Date类型的2022),再拷贝给d2,此过程会被优化,以提高效率。

如果不想让下面的隐式类型转换发生,那就用explicit修饰构造函数。

class Date
{
public:
    explicit Date(int year)
    {
        _year = year;
    }
private:
    int _year;
};
​
int main()
{
    Date d1(1000);  //d1不受影响
    Date d2 = 1000;  //d2因涉及类型转换,初始化失败
    return 0;
}

无法转换:

static静态成员

🤔如果我想要知道A类型的对象创建了多少个,要怎么办呢?

其实可以创建一个全局变量count来计数,但是,这种方式的缺点在于:

因为是全局的,人人都可以访问。

我们想要的count是:与A捆绑起来,别人访问不了,这个count就专门为A计数。

对于这个问题,在学习了static静态成员之后,我们就知道要怎么处理了。

概念:

声明为static的类成员称为类的静态成员

用static修饰的成员变量,称之为静态成员变量;

用static修饰的成员函数,称之为静态成员函数。

注:静态成员变量一定要在类外 进行 定义/ 初始化。

像这样:

class A
{
private:
    static int count;  //类里声明
};
​
int A::count = 0;     //类外初始化

了解:为什么静态成员一定要在类外初始化?

因为静态成员属于整个类,它被所有的对象所共享。

如果放在类里面初始化,当有多个对象存在时,每个对象里都含一份该静态成员,造成矛盾。

说明:

1.静态成员为所有类对象所共享,不属于某个具体的对象,存放在静态区。

class Date
{
private:
    static int _year;  //_year在静态区
    int _month;        //_month在对象里面。若对象在栈区,它就在栈区。
};

2.静态成员变量必须在类外定义,定义时不添加static关键字,类中只是声明。

3.怎么访问静态成员?

➡️如果它是公有的:可用 类名::静态成员 或者 对象.静态成员 来访问。

class A
{
public:
    A (){
        count++;
    }
    static int count;  
};
​
int A::count = 0;  
​
int main()
{
    A a1;
    cout << A::count << endl;  //用类域来访问
    cout << a1.count << endl;  //用对象来访问。这里不是说在a1里找,只是帮助突破类域去找
    return 0;
}

➡️如果是私有的:通过公有的函数来访问。

class A
{
public:
    A(){
        count++;
    }
    int GetCount() {
        return count;   //可以返回count的值
    }
    
private:
    static int count;  
};
​
int A::count = 0;  
​
int main()
{
    A a1;
    cout << a1.GetCount() << endl;  //通过GetCount()来访问count
    return 0;
}

4.静态成员函数没有隐藏的this指针,仅能访问静态的成员变量,不能访问任何非静态成员。

5.静态成员也是类的成员,受public、protected、private 访问限定符的限制。

友元

什么是友元

类的私有成员,一般情况下,外界是无法访问的。但实际上,private / protected并非是一堵密不透风的墙,

它对外开了个小口子,我们可以通过小口子访问私有成员。这个小口子就是友元。

友元是C++中的一种关系:像朋友一样亲密到可以访问私人空间的关系。发生在函数和类之间 or 类和类之间。

通过友元的关系,可以让一个函数or类 访问另一个类中的私有成员(private / protected)。

关键字:friend

分类:友元函数 友元类

➡️友元函数

友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,

不属于任何类,但需要在类的内部声明。

声明格式:friend 类型 函数名 (参数);

例:

class A
{
public:
    A() {
        a = 10;
  }
private:
    int a;
    friend void Print(const A& obj);   //友元的声明
};
​
void Print(const A& obj) {
    printf("%d", obj.a);   //访问了私有成员a
}
​
int main()
{
    A a1;
    Print(a1);
    return 0;
}

结果:

说明:

1.友元函数可访问类的私有和保护成员,但不是类的成员函数。

2.友元函数不能用const修饰。

3.友元函数可以在类定义的任何地方声明,不受类访问限定符限制。

4.一个函数可以是多个类的友元函数。

5.友元函数的调用与普通函数的调用原理相同。

➡️友元类

我们不仅可以将一个函数声明为一个类的朋友,也可以将一个类声明为另一个类的朋友。

这就是友元类。

友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。

声明格式:friend class 类名;

示例:

class A;   //注意:Print之前要声明一下A!
​
class Print
{
public:                           
    void print(const A& obj);    //如果前面没有声明A,这里会不知道A是什么,导致报错
};
​
class A
{
public:
    A() {
        a = 10;
  }
private:
    int a;
    friend class Print;
};
​
//类外定义print
void Print::print(const A& obj) {
    printf("%d", obj.a);
}
​
int main()
{
    A a1;
    Print p;
    p.print(a1);
    return 0;
}

结果:

说明:

1.友元关系是单向的,不具有交换性。

声明A是B的友元,不代表B也是A的友元。

2.友元关系不能传递。

如果C是B的友元, B是A的友元,则不能说明C是A的友元。

3.友元关系不能继承,这个在继承那边再详说。

最后,友元能少用就少用!

虽说友元有助于数据的共享,但它也有副作用:打破了封装,会破坏信息的隐蔽性。

内部类

(了解)

概念:如果一个类定义在另一个类的内部,这个内部类就叫做内部类。

如:

class Outside
{
private:
    int a;
​
    class Inside
    {
    private:
        int b;
    };
};

内部类是一个独立的类,它不属于外部类,更不能通过外部类的对象去访问内部类的成员。

外部类对内部类没有任何优越的访问权限。

说明:

1.内部类可以定义在外部类的public、protected、private都是可以的。

2.注意内部类可以直接访问外部类中的static成员,不需要外部类的对象/类名。

3.内部类天生就是外部类的友元。但是外部类不是内部类的友元。

class Outside
{
private:
    static int a;
    int b;
​
    class Inside    
    {
    public:
        void Print(const Outside& obj) {
            cout << a << endl;          //√,可以直接访问外部类中的static成员
            cout << obj.b << endl;      //√
        }
    private:
        int b;
    };
};

4.sizeof(外部类)=外部类,和内部类没有任何关系。

我们来证明一下:

class Outside
{
private:
    int a;
​
    class Inside
    {
    private:
        int b;
    };
};
​
int main()
{
    cout << sizeof(Outside);
    return 0;
}

结果:

可见,Inside不在Outside里。

实际上,它们是并列的关系,只是你从外部访问Inside,要受到Outside类域的限制。

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

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

相关文章

什么是主动元数据管理?有何优势?

元数据是描述数据的数据&#xff0c;它提供数据的来源、含义、位置、所有权和创建等信息&#xff0c;主要用于跟踪、分类和分析。 元数据管理则是对元数据的创建、存储、整合、控制的一整套流程&#xff0c;是数据治理过程的一部分&#xff0c;能够支持基于元数据的相关需求和…

NFT Insider#106:The Sandbox 与 Light Matrix 以及鲁比尼拳击场达成战略合作

引言&#xff1a;NFT Insider由NFT收藏组织WHALE Members、BeepCrypto联合出品&#xff0c;浓缩每周NFT新闻&#xff0c;为大家带来关于NFT最全面、最新鲜、最有价值的讯息。每期周报将从NFT市场数据&#xff0c;艺术新闻类&#xff0c;游戏新闻类&#xff0c;虚拟世界类&#…

Android12之解析/proc/pid进程参数(一百六十四)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

python通过tkinter制作词云图工具

一、基本功能 1.采取上传文本文档&#xff08;仅支持.txt格式&#xff09;的方式统计词频 2.背景图形样式可选择已经设定好的&#xff0c;也可选择本地上传的&#xff08;支持.png .jpg .jpeg格式&#xff09; 3.本地上传的图片需要进行抠图处理&#xff0c;并将抠图结果保存…

大乘数法 -Java

题目链接&#xff1a;https://www.nowcoder.com/practice/c4c488d4d40d4c4e9824c3650f7d5571?tpId196&tqId37177&rp1&ru/exam/company&qru/exam/company&sourceUrl%2Fexam%2Fcompany&difficultyundefined&judgeStatusundefined&tags&titl…

SAP 批量删除变式

使用事务码se38进入变式&#xff0c;通过搜索帮助选中一个变式&#xff0c;点击显示。 点击目录&#xff0c;会显示所有的变式名称。 会显示当前程序的所有变式&#xff0c;然后点击删除按钮&#xff0c;选择需要删除的变式。

CVPR2023 RIFormer, 无需TokenMixer也能达成SOTA性能的极简ViT架构

编辑 | Happy 首发 | AIWalker 链接 | https://mp.weixin.qq.com/s/l3US8Dsd0yNC19o7B1ZBgw project, paper, code Token Mixer是ViT骨干非常重要的组成成分&#xff0c;它用于对不同空域位置信息进行自适应聚合&#xff0c;但常规的自注意力往往存在高计算复杂度与高延迟问题。…

FP130A 封装SOT23-5L 轨道电流测量IC

FP130A 封装SOT23-5L 轨道电流测量IC 一般说明 FP130A是一种宽共模范围高侧轨电流测量IC。它适用于电源系统&#xff0c;如电池充电器或开关电源的应用。它包括一个差分输入放大器和一个具有发射极输出的NPN晶体管。有三个外部电阻&#xff0c;轨道电流信号可以很容易地转换为I…

VR软件与管理后台的协议(微信扫码)

一、微信扫码登录 1、设计流程&#xff1a; ①、VR软件界面生成二维码&#xff0c;二维码中携带跳转小程序的链接及设备号、公司ID&#xff1b;用户通过扫码进入微信小程序点击界面一键启动&#xff0c;开始完善个人信息。 ②、用户点击一键启动&#xff0c;用户信息的授权状态…

入门人工智能 —— 学习 python 使用 IDE :vscode 完成编程 (2)

入门人工智能 —— 学习 python 使用 IDE &#xff1a;vscode 完成编程 &#xff08;2&#xff09; 安装和配置 VSCode创建和运行 Python 代码使用 VSCode 的调试功能 在上一篇文章中&#xff0c;介绍了如何入门人工智能编程&#xff0c;并开始了学习 Python 编程语言的基础知识…

润和软件HopeStage与上海瑞美云LIS系统管理软件完成产品兼容性互认证

近日&#xff0c;江苏润和软件股份有限公司&#xff08;以下简称“润和软件”&#xff09;HopeStage 操作系统与上海瑞美电脑科技有限公司&#xff08;以下简称“上海瑞美”&#xff09;瑞美云LIS系统管理软件完成产品兼容性测试。 测试结果表明&#xff0c;企业级通用操作系统…

NFTScan NFT API 在 NFTFi 开发中的应用

NFTFi 是“NFT”和“Finance”的缩写&#xff0c;旨在“增加 NFT 流动性&#xff0c;提供现金流”&#xff0c;NFTFi 是为 NFT 提供金融实用性的去中心化协议和应用程序的新兴生态系统&#xff0c;及使用 NFT 作为基础层在其上建设经济基础设施。 在实践中&#xff0c;NFTFi 协…

yolov7中Concat之后加注意力模块(最复杂的情况)

1、common.py中找到Concat模块&#xff0c;复制一份 2、要传参进来&#xff0c;dim通道数 3、然后找yolo.py模块&#xff0c;添加 4、yaml里替换 5、和加的位置也有关系

20 Spring Boot整合Redis

一、Redis简介 简单来说 Redis 就是一个使用 C 语言开发的数据库&#xff0c;不过与传统数据库不同的是 Redis 的数据是存在内存中的 &#xff0c;也就是它是内存数据库&#xff0c;所以读写速度非常快&#xff0c;因此 Redis 被广泛应用于缓存方向。 另外&#xff0c;Redis 除…

c++ vs2019 cpp20 规范,set源码分析

&#xff08;1&#xff09;set模板和map模板都是继承于一个父类 所以没有再详细注释。维持红黑树主要的功能都在父类_Tree里了&#xff0c;比如节点的添加&#xff0c;删除&#xff0c;查找。父类红黑树的操作&#xff0c;并不依赖于特定的数据类型。做到了父类模板的通用性。…

Linux学习之MySQL连接查询

接上一篇 连接查询 连接查询也中多表查询&#xff0c;常用于查询来自于多张表的数据&#xff0c;通过不同的连接方式把多张表组成一张新的临时表&#xff0c;再对临时表做数据处理。 #表基础信息&#xff0c;内容可从上一篇博客中查看 mysql> desc departments; ---------…

第15章_锁: (表级锁、页级锁、行锁、悲观锁、乐观锁、全局锁、死锁)

3.2 从数据操作的粒度划分&#xff1a;表级锁、页级锁、行锁 为了提高数据库并发度&#xff0c;每次锁定的数据范围越小越好&#xff0c;理论上每次只锁定当前操作的数据的方案会得到最大的并发度&#xff0c;但管理锁是很耗资源&#xff08;涉及获取、检查、释放锁等动作)。因…

我总结的《149个Python面试题.pdf》,都是干货!

大家好&#xff0c;我是涛哥。 很多小伙伴找Python面试资料&#xff0c;所以为了方便大家&#xff0c;涛哥我整理了《149个Python面试干货》&#xff0c;方便大家进行学习&#xff0c;尤其是要面试学习的同学可以重点学起来。 第一个部分就是讲Python基础相关内容 第二个部分…

JAVA毕业设计097—基于Java+Springboot+Vue+uniapp的医院挂号小程序系统(源码+数据库)

基于JavaSpringbootVueuniapp的医院挂号小程序系统(源码数据库)097 一、系统介绍 本系统前后端分离(网页端和小程序端都有) 本系统分为管理员、医院、用户三种角色(角色菜单可自行分配) 用户功能&#xff1a; 注册、登录、医院搜索、最新资讯、医生搜索、挂号预约、挂号记…

由于找不到msvcp120.dll无法继续执行代码,重新安装相关软件

在我们的生活中&#xff0c;计算机已经成为不可或缺的工具&#xff0c;我们依赖它来进行工作、学习和娱乐。然而&#xff0c;当我们在使用计算机时&#xff0c;有时会遭遇一些令人烦恼的问题&#xff0c;例如“找不到 msvcp120.dll 无法继续执行代码”的错误提示。这究竟是什么…