【C++入门到精通】C++入门 —— 类和对象(初始化列表、Static成员、友元、内部类、匿名对象)

 

目录

一、初始化列表

⭕初始化列表概念

⭕初始化列表的优点

⭕使用场景

⭕explicit关键字

二、Static成员

⭕Static成员概念

🔴静态数据成员:

🔴静态函数成员:

⭕使用静态成员的优点

⭕使用静态成员的注意事项

三、友元

⭕友元的概念

⭕类友元

⭕函数友元

 四、内部类

⭕内部类的概念

⭕内部类的特点

五、匿名对象

⭕匿名对象概念

⭕匿名对象的作用

六、总结


前言

        这一篇文章是上一篇的续集(这里有上篇链接)前面我们讲了C语言的基础知识,也了解了一些数据结构,并且讲了有关C++的命名空间的一些知识点以及关于C++的缺省参数、函数重载,引用 和 内联函数。也相信大家都掌握的不错,接下来博主将会带领大家继续学习有关C++比较重要的知识点——类和对象(初始化列表、Static成员、友元、内部类、匿名对象)。下面话不多说坐稳扶好咱们要开车了。

一、初始化列表

初始化列表概念

        在C++中,初始化列表是一种在对象或类的构造函数中初始化成员变量的特殊语法。它在构造函数的参数列表之后(详细介绍构造函数),使用冒号分隔,后跟成员初始化列表。

初始化列表的语法如下所示:

ConstructorName(Initialization1, Initialization2, ...)

        其中, ConstructorName 是构造函数的名称, Initialization 是成员的初始化,可以包括成员变量、常量、引用以及调用其他构造函数等。

⭕初始化列表的优点

1. 初始化成员变量:使用初始化列表可以直接在构造函数中初始化成员变量,而不需要在构造函数体内分别对每个成员进行赋值。
2. 常量成员初始化:对于类中的常量成员,只能在初始化列表中进行初始化,而不能在构造函数体内赋值。
3. 避免无效构造:初始化列表可以避免在构造函数体内对成员变量进行默认初始化,然后再赋予新值的过程,从而提高效率。
4. 初始化顺序控制:使用初始化列表可以控制成员变量的初始化顺序,而不仅仅是它们在类中的声明顺序。

下面这段代码,展示了如何在构造函数中使用初始化列表初始化成员变量:

class MyClass {
private:int num;double value;public:MyClass(int n, double v) : num(n) , value(v) {// 构造函数体}
};

        在上述示例中, MyClass 类的构造函数使用初始化列表初始化了成员变量 numvalue ,分别使用参数 nv 来进行初始化。

        注意:冒号后面的代码就是初始化列表,其中 num(n) 表示将参数 n 的值赋给成员变量 numvalue(v) 表示将参数 v 的值赋给成员变量 value

⭕使用场景

1、每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次)

2、类中包含以:引用成员变量,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};

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

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

⭕explicit关键字

        在C++中,explicit 是一个关键字,用于修饰类的构造函数。它的主要作用是防止隐式类型转换,限制只能进行显示(显式)的类型转换,对于单个参数或者除第一个参数无默认值其余均有默认值的构造函数,还具有类型转换的作用。

        当一个构造函数被声明为 explicit 时,它将不会被用于隐式转换。这意味着在使用该构造函数创建对象时,不能使用隐式转换来将参数类型转换为构造函数所需的类型,而必须使用显式的方式进行类型转换

下面我会用几行代码来说明 explicit 关键字的使用:

class MyClass {
private:int num;public:explicit MyClass(int n) : num(n) {// 构造函数体}
};int main() {MyClass obj1(5);      // 直接调用构造函数,隐式转换不起作用MyClass obj2 = 10;   // 错误!使用了隐式转换, explicit构造函数无法隐式地将int类型转换为MyClass类型MyClass obj3 = MyClass(10); // 正确!使用显式转换return 0;
}

        在上述示例中, MyClass 类的构造函数被声明为 explicit ,当我们创建对象时,不能使用隐式转换方式将整型参数转换为 MyClass 类型的对象。因此, MyClass obj2 = 10; 这行代码会引发编译错误。而 MyClass obj3 = MyClass(10); 这行代码是合法的,它使用显式转换方式将整型参数转换为 MyClass 类型的对象。

二、Static成员

Static成员概念

        静态(static)成员是类的成员,而不是对象的成员。静态成员在类的所有对象之间共享,并且它们不与任何特定的对象关联,可以将静态成员分为两个类型:静态数据成员和静态函数成员。

🔴静态数据成员:

        静态数据成员是与类关联的变量,而不是与类的对象关联的。它们存储在类的一个独立的存储区域中,而不是存储在类的对象中。静态数据成员在类的所有对象之间共享。可以通过类名加作用域解析运算符(::)来访问静态数据成员。

   静态数据成员需要在类的声明中进行定义,并且在类外进行初始化。例如:

   class MyClass {private:static int count; // 静态数据成员的声明public:// 静态数据成员的初始化static int initialize;// ...};int MyClass::count = 0; // 静态数据成员的定义和初始化

静态数据成员被所有类的对象共享,因此它们的值在多个对象之间是共享的。

🔴静态函数成员:

        静态函数成员是与类关联的函数,而不是与类的对象关联的。静态函数成员可以在不创建类的对象的情况下被调用,通过使用类名加作用域解析运算符(::)来访问静态函数成员

   静态函数成员可以访问类的静态数据成员,但不能访问非静态的数据成员。静态函数成员在类的对象上操作的是静态成员,而不是对象的特定实例。 

   class MyClass {private:static int count; // 静态数据成员的声明public:static void increment() {count++;   // 静态函数成员可以访问静态数据成员}};int MyClass::count = 0; // 静态数据成员的定义和初始化int main() {MyClass::increment(); // 调用静态函数成员return 0;}

静态函数成员不需要通过类的对象进行调用,而是直接通过类名调用。

⭕使用静态成员的优点

        静态成员能够提供在类的所有对象之间共享的数据、全局访问的能力、一致性和效率的优势,以及更好的命名空间管理。这使得它们在某些情况下非常有用,并可以提高代码的可维护性和性能。

        1. 共享数据:静态数据成员在类的所有对象之间共享,它们只有一个副本。这意味着无论创建了多少个对象,它们都可以访问和修改同一个静态数据成员,从而实现数据的共享。这对于存储一些在类的所有对象中都具有相同值或状态的数据非常有用。例如,可以使用静态成员来记录某个类实例的数量,或者作为全局设置信息的存储器。

        2. 全局访问:静态数据成员和静态函数成员都可以在不创建类对象的情况下直接访问和调用。这使得它们可以在类的外部被其他类、函数或文件访问,并且不需要通过类的对象进行访问。这提供了一种全局访问数据和功能的方式,而无需创建类对象。例如,可以通过类名访问静态数据成员来获取全局配置信息,或者直接调用静态函数成员来执行某些全局操作。

        3. 一致性和效率:静态数据成员在整个类的对象之间保持一致的值,无论创建了多少个对象,它们始终具有相同的状态。这可以提高代码的一致性和可维护性。另外,由于静态数据成员只有一个副本,因此可以节省内存空间。而静态函数成员在调用时无需创建类的对象,可以直接通过类名调用,提高了代码的效率。

        4. 访问权限控制:静态成员可以被用于实现一些对于类的所有对象具有一致性的配置、计数或限制。通过将这些成员声明为私有的,可以确保只有类的成员函数可以访问和修改它们,从而保证了对其状态的控制。这允许在类中进行一些特殊的操作,可以确保只有类内部的特定成员函数能够对静态成员进行操作和修改,而外部代码无法直接访问。

        5. 命名空间扩展:静态成员可以用于扩展类的命名空间。通过在类中添加静态成员,可以将相关的函数和数据组织在一起,提供更好的命名空间管理,避免全局名称冲突。这使得代码更具可读性和可维护性,因为相关的函数和数据在类的范围内是分组的,并且可以通过类名进行访问。

⭕使用静态成员的注意事项

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

🚨静态成员可以被类的所有对象共享,所以在修改静态数据成员时应谨慎考虑它们的影响范围。
🚨静态数据成员在类外部定义和初始化,并且需要在类的声明中进行声明。
🚨静态函数成员不能访问非静态的数据成员,因为静态函数成员不与任何特定对象关联。

三、友元

⭕友元的概念

        友元(friend)是一种机制,允许一个类或函数访问另一个类的私有成员。通过友元关系,可以将某个外部实体(类或函数)授权以特殊的方式访问另一个类的非公开成员,而不需要违反封装的原则,友元可以分为两种类型:类友元和函数友元。

     注意:友元关系是单向的。例如,如果类A声明了类B为友元,使得B可以访问A的私有成员,这并不意味着A能够自动访问B的私有成员。友元关系需要在每个需要访问私有成员的类或函数中单独声明。友元关系可以破坏封装性因为它使得另一个类或函数可以访问私有成员。因此,应该谨慎使用友元机制,只在确实需要访问私有成员的情况下使用。同时,友元应尽可能地减少,以保持良好的封装性和代码可读性。

⭕类友元

        可以将一个类声明为另一个类的友元类。这将使得友元类可以访问被授权类的私有成员。在类的定义中使用  friend 关键字声明友元类,并且该声明通常放在被授权类的私有部分或公有部分的起始位置,被授权类的所有成员对友元类的所有成员都具有访问权限

class MyClass {
private:// 声明友元类friend class FriendClass;int privateData;public:// 公有成员
};class FriendClass {
public:void accessPrivateData(const MyClass& obj) {// 可以访问MyClass的私有成员int data = obj.privateData;}
};

在上面的代码中,FriendClass 被声明为 MyClass 的友元类,因此在 FriendClass 中可以访问 MyClass 的私有成员 privateData  

⭕函数友元

        可以将一个函数声明为另一个类的友元函数。这将使得友元函数可以直接访问被授权类的私有成员。在类的定义中使用  friend 关键字声明友元函数。被授权类的所有成员对友元函数具有访问权限。

class MyClass {
private:int privateData;public:// 声明友元函数friend void friendFunction(const MyClass& obj);
};void friendFunction(const MyClass& obj) {// 可以访问MyClass的私有成员int data = obj.privateData;
}

        在上面的代码中,friendFunction 被声明为  MyClass 的友元函数,因此在 friendFunction 中可以直接访问  MyClass 的私有成员  privateData 

        友元是一种特殊的关系,允许一个类或函数访问另一个类的私有成员。友元可以是类或函数,并通过使用  friend 关键字进行声明。友元关系在某些情况下是有用的,但应该谨慎使用。

 四、内部类

内部类的概念

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

内部类的特点

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;
}

五、匿名对象

⭕匿名对象概念

        匿名对象指的是在没有被命名的情况下创建的临时对象。它们在表达式中被直接使用,并且通常用于一次性的操作或作为函数调用的参数。匿名对象的创建方式是在类名后紧跟一对小括号,即类名后面加上一对空括号,或者在构造函数后调用无参构造函数。

class MyClass {
public:MyClass() {// 构造函数代码}void doSomething() {// 成员函数代码}
};int main() {// 创建匿名对象并调用成员函数MyClass().doSomething();// 将匿名对象作为函数参数someFunction(MyClass());return 0;
}

        在上面的代码中,MyClass().doSomething() 创建了一个匿名对象,并在该对象上调用了doSomething() 成员函数。同样地,someFunction(MyClass()) 将匿名对象作为函数someFunction 的参数。

        匿名对象是在没有被命名的情况下直接使用的临时对象。它们适用于一次性操作或作为函数调用的参数,并且通常用于临时任务。匿名对象的生命周期仅限于所在的表达式。但要注意匿名对象没有具名对象的灵活性和可重用性,因此在需要引用对象或保留对象状态的情况下,最好使用具名对象。

⭕匿名对象的作用

        匿名对象在某些情况下非常有用,特别是在需要执行一系列临时操作时。由于匿名对象没有被命名,也无法再次访问,因此它们通常被用于临时操作,而不是保存数据。匿名对象的生命周期仅限于所在的表达式,一旦表达式结束,匿名对象将被销毁。

        匿名对象还可以用于链式调用方法。这种用法允许在一行代码中依次调用多个成员函数,并对同一个对象进行串联操作。

MyClass().doSomething().doSomethingElse().processData();

在面的代码中,每个成员函数都返回一个新的临时对象,这样就可以在一行代码中依次调用多个成员函数。

        由于匿名对象没有被命名,无法在其作用域之外引用它。因此,如果需要在多个地方使用相同的对象或需要保留对象的状态,最好创建一个具名对象来替代匿名对象。

六、总结

        在上面我们介绍了:初始化列表、静态成员、友元、内部类和匿名对象,并且博主提供了对这些概念的全面介绍,帮助您理解和应用它们在C++编程中的作用和用法。

        在初始化列表部分,我们了解了初始化列表的概念和优点,包括提高效率和简化代码。我们还学习了explicit关键字的作用和使用场景。

        在静态成员部分,我们探讨了静态数据成员和静态函数成员的概念,并阐述了使用静态成员的优点,如共享数据、全局访问和一致性。我们还提到了使用静态成员时需要注意的事项。

        在友元部分,我们理解了友元的概念,并学习了类友元和函数友元的用法。我们明白了友元允许其他类或函数访问私有成员的能力,同时强调了谨慎使用友元的重要性。

        在内部类部分,我们了解了内部类的概念和特点。我们知道内部类是在另一个类的内部定义的类,并且具有访问外部类的成员的能力。

        最后,在匿名对象部分,我们学习了匿名对象的概念和作用。我们了解到匿名对象通常用于一次性操作或作为函数调用的参数,但它们的生命周期仅限于所在的表达式。

温馨提示

        感谢您对博主文章的关注与支持!在阅读本篇文章的同时,我们想提醒您留下您宝贵的意见和反馈。如果您喜欢这篇文章,可以点赞、评论和分享给您的同学,这将对我提供巨大的鼓励和支持。另外,我计划在未来的更新中持续探讨与本文相关的内容。我会为您带来更多关于C++以及编程技术问题的深入解析、应用案例和趣味玩法等。请继续关注博主的更新,不要错过任何精彩内容!

        再次感谢您的支持和关注。我们期待与您建立更紧密的互动,共同探索C++、算法和编程的奥秘。祝您生活愉快,排便顺畅!

       
 

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

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

相关文章

go 中的代码漏洞检查

前言 不知道大家在开发 go 项目中有没有遇到过一些第三方包或者官方包中出现漏洞的问题&#xff0c;这些漏洞可能会影响到代码的功能、性能或者安全性。 现在针对这一问题&#xff0c;go 团队提供了 govulncheck 工具&#xff0c;帮助开发者快速地发现和修复这些漏洞。 什么…

C/C++开发,opencv与qt结合播放视频

目录 一、qt_ui创建 1.1 ui设置 1.2 ui及代码输出保存 二、创建工程 2.1 工程目录及编译设置 2.2 源码设计 三、编译及测试 3.1 程序编译 3.2 程序运行 首先声明&#xff0c;这是一个OpenCV 3学习文档的案例&#xff0c;但是说明有些过于省略&#xff0c;只有一些简短的代码…

计算机毕设 深度学习人体跌倒检测 -yolo 机器视觉 opencv python

文章目录 0 前言1.前言2.实现效果3.相关技术原理3.1卷积神经网络3.1YOLOV5简介3.2 YOLOv5s 模型算法流程和原理4.数据集处理3.1 数据标注简介3.2 数据保存 5.模型训练 6 最后 0 前言 &#x1f525; 这两年开始毕业设计和毕业答辩的要求和难度不断提升&#xff0c;传统的毕设题…

Clion开发Stm32之温湿度传感器(DS18B20)驱动编写和测试

前言 涵盖之前文章: Clion开发STM32之HAL库GPIO宏定义封装(最新版)Clion开发stm32之微妙延迟(采用nop指令实现)Clion开发STM32之日志模块(参考RT-Thread) DSP18B20驱动文件 头文件 /*******************************************************************************Copy…

OAuth机制_web站点接入微软azure账号进行三方登录

文章目录 ⭐前言⭐微软三方登录流程&#x1f496; web站点获取微软账号流程&#x1f496; node封装微软登录接口&#x1f496; webapp 自定义code换token&#x1f496; 调用 Microsoft Graph API&#x1f496; 前端唤醒authlink进行登录回调逻辑 ⭐结束 ⭐前言 大家好&#xf…

sublime配置less的一些坑(1)

仅在sublime的Install Package安装保存less报错 在sublime的Install Package安装less 打开sublime软件,按住CtrlShiftP组合键,弹出的界面中选择Install Package 选中后enter或者回车。等会弹出一个弹窗,大致意思是说你已经成功安装了package control。如果你在此之前已经安装了…

【论文精读】MemSum: 基于历史决策的多步长文本抽取式摘要方法

前言 论文分享 来自2022ACL的长文本抽取式摘要方法论文 MemSum: Extractive Summarization of Long Documents Using Multi-Step Episodic Markov Decision Processes 自动文本摘要抽取可以分为抽取式(extractive)和抽象性式(abstractive)&#xff0c;抽取式方法将摘要抽取任…

【Uniapp】支付链转二维码

前言 提示&#xff1a;这个是一个很小的项目&#xff0c;大概30分钟就能搞定 实现方式&#xff1a;输入支付代码&#xff0c;存储到对应的数据库表中&#xff0c;二维码访问一个PHP文件通过id来进行重定向&#xff0c;这样就可以使每张二维码都是固定的&#xff0c;替换二维码…

11-矩阵的运算_加减法_数乘_转置

矩阵的运算 加法&#xff0c;数乘&#xff0c;减法&#xff0c;转置 矩阵的加减 矩阵的加法就是矩阵的对应位置相加&#xff0c;减法也是一样就是对应位置相减 数乘 转置 转置的操作和向量是一样的&#xff0c;就是把 aij 变成 aji&#xff0c;把行和列互换一下 对于矩阵而…

【Android常见问题(五)】- Flutter项目性能优化

文章目录 知识回顾前言源码分析1. 渲染过程2. 分析工具3. 优化方法合理使用const关键词合理使用组件管理着色器编译垃圾 知识回顾 前言 项目迭代开发一定程度后&#xff0c;性能优化是重中之重&#xff0c;其中包括了包体积&#xff0c;UI 渲染、交互等多个方面。 通过 Flutt…

Zotero ubuntu2023安装 关联 ubuntu文献翻译

一、准备下载的软件&#xff1a; Zotero | Downloads 1. Zotero-6.0.26_linux-x86_64.tar.bz2 下面是插件 zotfile-5.1.2-fx.xpi zotero-pdf-translate.xpi jasminum-v0.2.6.xpi 2.2.5 Tampermonkey 4.11.crx 所准备的文件&#xff0c;都已经在这个链接的压缩包下面 …

动态内存管理学习分享

动态内存管理学习分享 1. 为什么存在动态内存分配2. 动态内存函数的介绍2.1 [malloc](https://legacy.cplusplus.com/reference/cstdlib/malloc/?kwmalloc)和[free](https://legacy.cplusplus.com/reference/cstdlib/free/?kwfree)2.1.1 实例 2.2 [calloc](https://legacy.cp…

小程序----配置原生内置编译插件支持sass

修改project.config.json配置文件 在 project.config.json 文件中&#xff0c;修改setting 下的 useCompilerPlugins 字段为 ["sass"]&#xff0c; 即可开启工具内置的 sass 编译插件。 目前支持三个编译插件&#xff1a;typescript、less、sass 修改之后可以将原.w…

持续贡献开源力量,棱镜七彩加入openKylin

近日&#xff0c;棱镜七彩签署 openKylin 社区 CLA&#xff08;Contributor License Agreement 贡献者许可协议&#xff09;&#xff0c;正式加入openKylin 开源社区。 棱镜七彩成立于2016年&#xff0c;是一家专注于开源安全、软件供应链安全的创新型科技企业。自成立以来&…

【消息中间件】原生PHP对接Uni H5、APP、微信小程序实时通讯消息服务

文章目录 视频演示效果前言一、分析二、全局注入MQTT连接1.引入库2.写入全局连接代码 二、PHP环境建立总结 视频演示效果 【uniapp】实现买定离手小游戏 前言 Mqtt不同环境问题太多&#xff0c;新手可以看下 《【MQTT】Esp32数据上传采集&#xff1a;最新mqtt插件&#xff08;支…

使用3ds Max粒子系统创建飞天箭雨特效场景

推荐&#xff1a; NSDT场景编辑器助你快速搭建可二次开发的3D应用场景 1. 设置箭头 步骤 1 打开 3ds Max。 打开 3ds Max 步骤 2 我使用多边形建模技术制作了一个简单的箭头&#xff0c;我将 在教程中使用。.max您可以从 下载部分。 箭头.max 步骤 3 将此箭头重命名为静态…

【计算复杂性理论】证明复杂性(八):命题鸽巢原理(Propositional Pigeonhole Principle)的指数级归结下界

往期文章&#xff1a; 【计算复杂性理论】证明复杂性&#xff08;Proof Complexity&#xff09;&#xff08;一&#xff09;&#xff1a;简介 【计算复杂性理论】证明复杂性&#xff08;二&#xff09;&#xff1a;归结&#xff08;Resolution&#xff09;与扩展归结&#xff…

CentOS 7.6使用yum安装stress,源码安装stree-ng 0.15.06,源码安装sysstat 12.7.2

cat /etc/redhat-release看到操作系统的版本是CentOS Linux release 7.6.1810 (Core)&#xff0c;uname -r可以看到内核版本是3.10.0-957.21.3.el7.x86_64 yum install stress sysstat -y安装stress和sysstat。 使用pidstat -u 5 1没有%wait项&#xff1a; 原因是CentOS 7仓…

13.7 CentOS 7 环境下大量创建帐号的方法

13.7.1 一些帐号相关的检查工具 pwck pwck 这个指令在检查 /etc/passwd 这个帐号配置文件内的信息&#xff0c;与实际的主文件夹是否存在等信息&#xff0c; 还可以比对 /etc/passwd /etc/shadow 的信息是否一致&#xff0c;另外&#xff0c;如果 /etc/passwd 内的数据字段错…

用C语言构建一个手写数字识别神经网络

(原理和程序基本框架请参见前一篇 "用C语言构建了一个简单的神经网路") &#xff11;&#xff0e;准备训练和测试数据集 从http://yann.lecun.com/exdb/mnist/下载手写数字训练数据集, 包括图像数据train-images-idx3-ubyte.gz 和标签数据 train-labels-idx1-ubyte.…