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

news2024/11/16 15:58:50

 

目录

一、初始化列表

⭕初始化列表概念

⭕初始化列表的优点

⭕使用场景

⭕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;//OK
            cout << 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.coloradmin.cn/o/814814.html

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

相关文章

国际化警告Fall back to translate ‘creator‘ key with ‘zn‘ locale.

发现是自己粗心写错了一个单词 这个需要改成zh

OC对象内存布局与isa指针

文章目录 一、Objective-C的本质二、一个objc对象如何进行内存布局&#xff1f;考虑父类的情况三、一个objc对象的isa指针指向什么&#xff1f;有什么作用四、objc对象的类方法和实例方法有什么本质区别和联系&#xff1f; 一、Objective-C的本质 Objc的底层实现是C\C代码&…

微信小程序tab加列表demo

一、效果 代码复制即可使用&#xff0c;记得把图标替换成个人工程项目图片。 微信小程序开发经常会遇到各种各样的页面组合&#xff0c;本demo为list列表与tab组合&#xff0c;代码如下&#xff1a; 二、json代码 {"usingComponents": {},"navigationStyle&q…

goctl template一定制化服务配置生成

官网介绍&#xff1a; 模板&#xff08;Template&#xff09;是数据驱动生成的基础&#xff0c;所有的代码&#xff08;rest api、rpc、model、docker、kube&#xff09;生成都会依赖模板&#xff0c; 默认情况下&#xff0c;模板生成器会选择内存中的模板进行生成&#xff0c…

easyui实用点

easyui实用点 1.下拉框&#xff08;input框只能选不能手动输入编辑&#xff09; data-options"editable:false"//不可编辑2.日期框&#xff0c;下拉框&#xff0c;文本框等class class"easyui-datebox"//不带时分秒 class"easyui-datetimebox"…

口碑+丨香港邮政联合极智嘉建立全港首个机器人邮包分拣系统

近日&#xff0c;香港邮政与全球仓储机器人引领者极智嘉(Geek)在其中央邮件中心联手建立全港首个机器人包裹分拣系统。该全新系统采用极智嘉分运结合解决方案&#xff0c;每小时可处理达1,000个邮包&#xff0c;助力香港邮政利用创新科技简化邮包分拣流程、提升工作效率&#x…

allwinner 全志RS485调试,GPIO状态与万用表测量不同

全志RS485调试 思路&#xff1a;UART驱动中已经将485流控功能加进去了&#xff0c;所以我们只需要根据硬件原理图配置一下485脚的GPIO就行了。 硬件原理图&#xff1a; 将UART3 UART4的RTS脚配置为485流控脚就行&#xff0c; RX和TX不需要配置&#xff0c;在pinctrol已经配置好…

热风梳C22.2 NO.3亚马逊加拿大审核标准

加拿大是目前亚马逊所有站点中&#xff0c;商业规模大、发展势头迅猛的站点之一。亚马逊加拿大站每月吸引近1600万访客。其优势在于在加拿大&#xff0c;目前平台的竞争较小&#xff0c;商家容易出单。既然加拿大站有这么多优势&#xff0c;那产品上架需要有哪些检测认证合规方…

[MAUI 项目实战] 手势控制音乐播放器: 手势交互

原理 定义一个拖拽物&#xff0c;和它拖拽的目标&#xff0c;拖拽物可以理解为一个平底锅&#xff08;pan&#xff09;&#xff0c;拖拽目标是一个坑&#xff08;pit&#xff09;&#xff0c;当拖拽物进入坑时&#xff0c;拖拽物就会被吸附在坑里。可以脑补一下下图&#xff1…

腾讯地图点标记加调用

先看效果 PHP代码 <?phpnamespace kds_addons\edata\controller;use think\addons\Controller; use think\Db;class Maps extends Controller {// 经纬度计算面积function calculate_area($points){$totalArea 0;$numPoints count($points);if ($numPoints > 2) {…

Qt、Qt Creator下载、安装

一、Qt、Qtcreator简介 Qt是一个跨平台应用开发框架。 Qt Creator是一个跨平台的集成开发环境&#xff08;IDE&#xff09;&#xff0c;集成了Qt所提供的功能&#xff0c;可以单独下载使用&#xff0c;也可以结合Qt组合使用。 二、下载 下载地址&#xff1a;https://downloa…

2023 ChinaJoy | 移远通信携手高通,共创数字娱乐新体验

当前&#xff0c; 5G、AI、大数据等智能创新技术正以惊人的速度蔓延至越来越多的领域&#xff0c;从智能家居、智能交通、智能医疗到智能制造&#xff0c;改变了我们的工作和生活方式。 而在数字娱乐领域&#xff0c;智能创新技术也展现出了巨大的潜力。作为全球领先的物联网整…

13.5.5 【Linux】其他相关文件

除了前一小节谈到的 /etc/securetty 会影响到 root 可登陆的安全终端机&#xff0c; /etc/nologin 会影响到一般使用者是否能够登陆的功能之外&#xff0c;我们也知道 PAM 相关的配置文件在 /etc/pam.d &#xff0c;说明文档在 /usr/share/doc/pam-&#xff08;版本&#xff09…

牛客网Verilog刷题——VL47

牛客网Verilog刷题——VL47 题目答案 题目 实现4bit位宽的格雷码计数器。 电路的接口如下图所示&#xff1a; 输入输出描述&#xff1a; 信号类型输入/输出位宽描述clkwireIntput1时钟信号rst_nwireIntput1异步复位信号&#xff0c;低电平有效gray_outregOutput4输出格雷码计数…

管理ceph集群

文章目录 ceph的常用命令查看集群状态查看pg的状态查看mon节点状态查看osd的通用命令查看osd的容量查看osd池写入文件测试查看池的属性查看文件映射过程 添加磁盘删除磁盘 ceph的常用命令 查看集群状态 ceph osd pool application enable pool-name rbd #将池启用rbd功能 ceph…

Java集合框架-List、Set、Map

一、Java集合框架概述&#xff1a; 1.1 Collection接口继承树 JDK提供的集合API位于java.util包内。 Map接口继承树 1.2 Collection接口方法 Collection 接口 Collection 接口是 List、Set 和 Queue 接口的父接口&#xff0c;该接口里定义的方法既可用于操作 Set 集合&#…

Matlab进阶绘图第24期—悬浮柱状图

悬浮柱状图是一种特殊的柱状图。 与常规柱状图相比&#xff0c;悬浮柱状图可以通过悬浮的矩形展示最小值到最大值的范围&#xff08;或其他范围表达&#xff09;&#xff0c;因此在多个领域得到应用。 本文使用自己制作的Floatingbar小工具进行悬浮柱状图的绘制&#xff0c;先…

【Linux】Linux项目自动化构建工具 make/Makefile

目录 1. Makefile 是如何工作的 2. 依赖关系与依赖方法 3. .PHONY 4. Makefile 的特殊符号 写在最后&#xff1a; 1. Makefile 是如何工作的 make 是一个命令。 Makefile 是一个文件&#xff0c;当前目录下的一个文件。 我们先来上手写一个简单的 Makefile 文件&#…

火山引擎AB测试:广告实验深度打通巨量引擎,高效测试广告素材

更多技术交流、求职机会&#xff0c;欢迎关注字节跳动数据平台微信公众号&#xff0c;回复【1】进入官方交流群 近期&#xff0c;火山引擎AB测试DataTester上线了新版的广告AB实验&#xff0c;还推出了与巨量引擎深度打通的能力。用户可以在DataTester中直接进行广告落地页的创…

机器学习:异常检测

问题定义 anomaly&#xff0c;outlier&#xff0c; novelty&#xff0c; exceptions 不同的方法使用不同的名词定义这类问题。 应用 二分类 假如只有正常的数据&#xff0c;而异常的数据的范围非常广的话&#xff08;无法穷举&#xff09;&#xff0c;二分类这些不好做。另外就…