C++ 进阶:类相关特性的深入探讨

⭐在对C++ 中类的6个默认成员函数有了初步了解之后,现在我们进行对类相关特性的深入探讨!

🔥🔥🔥【C++】类的默认成员函数:深入剖析与应用(上)

               【C++】类的默认成员函数:深入剖析与应用(下)


目录

💯前言

💯再谈构造函数

(一)构造函数体赋值

(二)初始化列表

(三)explicit关键字

💯static成员

(一)静态成员变量

(二)静态成员函数

💯友元

(一)友元函数

(二)友元类

💯内部类

(一)定义与访问

(二)内部类的用途

💯总结


💯前言

在 C++ 编程中,类是构建复杂程序的基石。🌟它提供了一种将数据和操作数据的方法进行封装的机制,使得程序更加模块化、可维护和可扩展。在之前对类的学习中,我们已经了解了一些基本概念,如构造函数、拷贝构造函数和析构函数等。然而,类还有许多其他重要的特性,这些特性对于深入理解和掌握 C++ 编程至关重要。🎦本文将进一步探讨构造函数的更多细节,以及 Static 成员、友元、内部类等特性,并再次深入理解封装的概念。

 


💯再谈构造函数

 构造函数在 C++ 类中扮演着至关重要的角色。它主要用于对象的初始化操作。当创建一个类的对象时,构造函数会被自动调用


(一)构造函数体赋值

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

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

 ❗注意:

  1. 每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次)
  2. 类中包含以下成员,必须放在初始化列表位置进行初始化:
    🌠引用成员变量
    🌠const成员变量
    🌠自定义类型成员(且该类没有默认构造函数时)
    #include <iostream>// 自定义类 CustomClass 的定义
    class CustomClass {
    public:// 构造函数,接收一个整数值进行初始化CustomClass(int val) : value(val) {std::cout << "CustomClass constructor called with value: " << value << std::endl;}
    private:int value;
    };// 主类 MyClass 的定义
    class MyClass {
    public:int& ref; // 引用成员变量const int constVal; // const 成员变量CustomClass custom; // 自定义类型成员变量// 构造函数,接收一个引用、一个整数和一个整数作为参数MyClass(int& r, int v, int customVal) : ref(r), constVal(v), custom(customVal) {std::cout << "MyClass constructor called." << std::endl;}
    };int main() {int num = 10;// 创建 MyClass 对象,传入相应参数MyClass obj(num, 20, 30);return 0;
    }

    MyClass包含了引用成员变量、const成员变量和一个自定义类型的成员变量。在构造函数中,必须使用初始化列表来正确初始化这些特殊类型的成员变量。


  3. 尽量使用初始化列表初始化,因为不管你是否使用初始化列表,✅对于自定义类型成员变量,一定会先使用初始化列表初始化
    #include <iostream>class CustomType {
    public:CustomType(int val) : data(val) {std::cout << "CustomType constructor called with value: " << data << std::endl;}
    private:int data;
    };class MyClass {
    public:MyClass(int customVal) : customMember(customVal) {std::cout << "MyClass constructor called." << std::endl;}
    private:CustomType customMember;
    };int main() {MyClass obj(42);return 0;
    }

    在这个例子中,MyClass有一个自定义类型CustomType的成员变量customMember。当创建MyClass的对象时,即使在MyClass的构造函数中没有显式地写出初始化列表,但实际上编译器会先尝试使用初始化列表来初始化customMember,这就调用了CustomType的构造函数并输出相应信息。如果CustomType没有默认构造函数,那么就必须在MyClass的构造函数中显式地使用初始化列表来正确初始化customMember


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

    #include <iostream>class MyClass {
    public:MyClass(int a, int b, int c) : c_member(c), b_member(b), a_member(a) {std::cout << "Constructor called." << std::endl;}void printMembers() {std::cout << "a_member: " << a_member << std::endl;std::cout << "b_member: " << b_member << std::endl;std::cout << "c_member: " << c_member << std::endl;}private:int a_member;int b_member;int c_member;
    };int main() {MyClass obj(1, 2, 3);obj.printMembers();return 0;
    }


    在这个例子中,构造函数的初始化列表中成员变量的初始化顺序看起来是 c_memberb_membera_member💐但实际上成员变量的初始化顺序是由它们在类中的声明顺序决定的即先初始化 a_member,再初始化 b_member,最后初始化 c_member如果在初始化列表中打乱顺序,初始化的结果仍然是按照声明顺序进行的。


(三)explicit关键字

构造函数不仅可以构造与初始化对象,对于接收单个参数的构造函数,还具有类型转换的作用。 

接收单个参数的构造函数具体表现🌞: 

  1. 构造函数只有一个参数
  2. 构造函数有多个参数,除第一个参数没有默认值外,其余参数都有默认值
  3. 全缺省构造函数 
#include <iostream>class Date
{
public:// 1. 单参构造函数,没有使用 explicit 修饰,具有类型转换作用// explicit 修饰构造函数,禁止类型转换---explicit 去掉之后,代码可以通过编译explicit Date(int year): _year(year){}/*// 2. 虽然有多个参数,但是创建对象时后两个参数可以不传递,没有使用 explicit 修饰,具有类型转换作用// explicit 修饰构造函数,禁止类型转换explicit Date(int year, int month = 1, int day = 1): _year(year), _month(month), _day(day){}*/Date& operator=(const Date& d){if (this!= &d){_year = d._year;_month = d._month;_day = d._day;}return *this;}private:int _year;int _month;int _day;
};void Test()
{Date d1(2022);// 用一个整形变量给日期类型对象赋值// 实际编译器背后会用 2023 构造一个无名对象,最后用无名对象给 d1 对象进行赋值// 将 1 屏蔽掉,2 放开时则编译失败,因为 explicit 修饰构造函数,禁止了单参构造函数类型转换的作用
}

 上述代码可读性不是很好,用explicit修饰构造函数,将会禁止构造函数的隐式转换。

 有一个接受单个整数参数的构造函数Date(int year),用于初始化日期对象的年份部分。这个构造函数使用了explicit关键字修饰,这意味着它不能进行隐式类型转换。如果没有这个关键字,编译器可能会在某些情况下自动使用这个构造函数进行隐式的类型转换。

 


💯static成员

 

(一)静态成员变量

😃静态成员变量是属于类的变量,而不是属于某个具体的对象。它在整个类的所有对象之间共享。

  1.定义与初始化

  • 静态成员变量需要在类内声明,但不能在类内初始化(除了一些特殊的静态常量整数类型可以在类内初始化)。例如:
    class MyClass {
    public:static int staticVar;
    };
    int MyClass::staticVar = 0; // 在类外初始化

  2.访问方式

  • 可以通过类名直接访问静态成员变量,也可以通过对象访问,但通常建议通过类名访问,以体现其类属性。例如:
    MyClass obj;
    MyClass::staticVar = 10; // 通过类名访问
    obj.staticVar = 20; // 通过对象访问也是允许的,但不规范

(二)静态成员函数

🍎静态成员函数也是属于类的函数,它不依赖于具体的对象实例。

1.特点

  • 它只能访问静态成员变量和其他静态成员函数,因为它没有this指针指向具体的对象。例如:
    class MyClass {
    public:static int staticVar;static void staticFunction() {staticVar++; // 可以访问静态成员变量// 不能访问非静态成员变量,因为没有this指针}
    };

2.调用方式

  • 与静态成员变量类似,可以通过类名直接调用静态成员函数。例如:MyClass::staticFunction();

 


💯友元

友元机制允许一个类或函数访问另一个类的私有成员。它打破了类的封装性,但在某些特定情况下是非常有用的。

(一)友元函数

1.定义

  • 友元函数是在一个类中声明为友元的普通函数。它不是类的成员函数,但可以访问该类的私有成员。例如:
    class MyClass {
    private:int privateVar;
    public:friend void friendFunction(MyClass obj);
    };
    void friendFunction(MyClass obj) {// 可以访问obj的privateVarstd::cout << obj.privateVar << std::endl;
    }

❗说明:

  1. 友元函数可访问类的私有和保护成员,但不是类的成员函数
  2. 友元函数不能用const修饰
  3. 友元函数可以在类定义的任何地方声明,不受类访问限定符限制
  4. 一个函数可以是多个类的友元函数
  5. 友元函数的调用与普通函数的调用原理相同

(二)友元类

1.定义

  • 友元类是在一个类中声明为友元的另一个类。友元类的所有成员函数都可以访问声明它为友元的类的私有成员。例如:
    class MyClass {
    private:int privateVar;
    public:friend class FriendClass;
    };
    class FriendClass {
    public:void accessPrivate(MyClass obj) {// 可以访问obj的privateVarstd::cout << obj.privateVar << std::endl;}
    };

2.使用场景

  • 当两个类之间存在紧密的合作关系,需要相互访问对方的私有成员时,可以使用友元类。例如,一个图形绘制类和一个图形变换类可能需要相互访问对方的私有数据来实现复杂的图形操作。

💯内部类

🍄内部类是定义在另一个类内部的类。它具有一些特殊的性质和用途。

(一)定义与访问

1.定义

  • 内部类可以在一个外部类的任何部分定义,包括私有部分、保护部分和公共部分。例如:
    class OuterClass {
    private:int outerVar;class InnerClass {public:void innerFunction() {// 可以访问OuterClass的成员吗?这取决于具体情况}};
    };

2.访问

  • 外部类可以通过创建内部类的对象来访问内部类的成员。内部类也可以访问外部类的成员,但需要注意访问权限。如果内部类定义在外部类的公共部分,那么它可以像普通类一样被外部访问和使用。如果定义在私有部分,只有外部类的成员函数可以创建内部类的对象并访问其的成员。例如:
    OuterClass outerObj;
    OuterClass::InnerClass innerObj; // 创建内部类对象(如果InnerClass是公共的)
    outerObj.innerObj.innerFunction(); // 通过外部区
    outerObj.innerObj.innerFunction(); // 通过外部类对象访问内部类对象的成员(如果InnerClass是公共的且有合适的访问路径)

(二)内部类的用途

1.隐藏实现细节

  • 内部类可以将一些与外部类相关但又不想暴露给外部的实现细节封装起来。例如,一个复杂的容器类可能使用内部类来实现其内部的数据结构,如链表节点类可以作为容器类的内部类。

2.实现辅助功能

  • 可以利用内部类来实现一些辅助功能,这些功能与外部类紧密相关但又不适合作为外部类的直接成员函数。例如,一个文件读取类可能有一个内部类用于处理文件的缓冲和读取位置等细节。

💯总结

C++ 中类的这些特性为我们提供了强大的编程工具,让我们能够更好地组织和管理代码。希望本文能够帮助你更深入地理解 C++ 类的相关特性,提升你的编程能力。🚩🚩🚩


以后我将深入研究继承、多态、模板等特性,并将默认成员函数与这些特性结合,以解决更复杂编程问题!欢迎关注我👉【A Charmer】

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

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

相关文章

初阶数据结构【3】--单链表(比顺序表还好的一种数据结构!!!)

本章概述 前情回顾单链表实现单链表彩蛋时刻&#xff01;&#xff01;&#xff01; 前情回顾 咱们在上一章博客点击&#xff1a;《顺序表》的末尾&#xff0c;提出了一个问题&#xff0c;讲出了顺序表的缺点——有点浪费空间。所以&#xff0c;为了解决这个问题&#xff0c;我…

TypeScript 出现过的问题

不能将类型“unknown”分配给类型“string”。 不能直接将类型“unknown”分配给类型“string” /**** 【1 - 问题】会画红波浪线 ****/ window.document.title to?.meta?.title || /**** 【2 - 解决】解决红波浪线 ****/ const title: unknown to?.meta?.title || if …

QML 基本动画

在介绍完 QML 动画框架之后,现在我们来看看具体的动画及其用法。先从最常用的基本动画入手,这些动画包括:PropertyAnimation、ColorAnimation、Vector3dAnimation 和 PathAnimation 等,它们不仅能够帮助我们轻松地为应用程序添加动态效果,还能显著提升用户体验,使得界面更…

vue3 解决背景图与窗口留有间隙的问题

需要实现一个登录界面&#xff0c;login.vue的代码如下&#xff1a; <script> import { ref } from vue;export default {setup() {return {};}, }; </script><template><div id"login-container" class"login-container"><di…

中国古代数学的杰出研究成果之一 - 杨辉三角 - 怎么用go、C++进行编程解决

杨辉三角&#xff0c;又称帕斯卡三角形&#xff08;Pascals Triangle&#xff09;&#xff0c;是组合数学中的一个重要概念。它是一个三角形数组&#xff0c;其中每个数字是它上方左上方和右上方的数字之和。杨辉三角的每一行都代表了二项式展开式的系数&#xff0c;因此在数学…

利用 OBS 推送 WEBRTC 流到 smart rtmpd

webrtc whip 推流 & whep 拉流简介 RFC 定义 通用的 webrtc 对于 SDP 协议的交换已经有对应的 RFC 草案出炉了。这就是 WHIP( push stream ) & WHEP ( pull stream ) . WHIP RFC Link: https://www.ietf.org/archive/id/draft-ietf-wish-whip-01.html WHEP RFC Link:…

ubuntu 开启haproxy UI

一、修改haproxy.cfg nano /etc/haproxy/haproxy.cfg 添加一段 listen statsbind *:8080stats enablestats uri /uistats refresh 10sstats auth admin:123456stats admin if TRUE 重启 sudo systemctl restart haproxy 浏览器访问&#xff1a; http://192.168.31.182:80…

搜维尔科技:SenseGlove触觉反馈数据手套的用途和作用

无论是VR培训、遥控机器人、研究还是营销&#xff0c;我们的VR触觉手套都能让虚拟世界更具沉浸感和吸引力。借助我们的硬件和直观的软件开发工具&#xff0c;研究人员和开发人员可以创建真正的触觉交互。 VR培训 使用 SenseGlove进行虚拟现实训练可产生与现实训练类似的效果&a…

MySQL-CRUD-基础-(详解) ┗( ▔, ▔ )┛

目录 ❄️一、新增&#xff08;Create&#xff09;&#xff1a; ☑ 1、单行数据 全列插入&#xff1a; ☑ 2、指定列插入&#xff1a; ☑ 3、多行插入&#xff1a; ❄️二、查询&#xff08;Retrieve&#xff09;&#xff1a; ☑ 1、全列查询&#xff1a; ☑ 2、指定列查询&a…

【数据结构与算法】走进数据结构的“时间胶囊”——栈

大家好&#xff0c;我是小卡皮巴拉 文章目录 目录 引言 一.栈的基本概念 1.1 定义 1.2 特性 1.3 基本操作 二.栈的实现方式 2.1 顺序栈 2.2 链栈 三.顺序栈的实现 定义顺序栈的结构 初始化 入栈 检查栈是否为空 出栈 销毁 四.链栈的实现 定义链栈的结构 初始…

新版idea菜单栏展开与合并

新版idea把菜单栏合并了看着很是不习惯&#xff0c;找了半天原来在这里展开 ① 点击文件 -> 设置 ② 点击外观与行为 -> 外观 -> 合并主菜单和窗口标题 然后确定&#xff0c;重启即可

戴维南,叠加,稳态笔记

一点点学习笔记,仅做个人复习使用 节点电压分清电流电压源&#xff0c;电流源才能写在右边&#xff0c;容易混淆 叠加定理仅适用于线性电路&#xff0c;且不能用于计算功率&#xff0c;主要是方向&#xff0c;要看源的方向判断等效之后的&#xff0c;受控源不参与除源&#x…

数据库表的创建

运用的环境是pychram python3.11.4 创建一个表需要用到以下语法 注释已经写清楚各种语法的含义&#xff0c;记住缩进是你程序运行的关键&#xff0c;因为程序是看你的缩进来判断你的运行逻辑&#xff0c;像我这个就是缩进不合理导致的报错 那么今天分享就到这里&#xff0c;谢…

android11 usb摄像头添加多分辨率支持

部分借鉴于&#xff1a;https://blog.csdn.net/weixin_45639314/article/details/142210634 目录 一、需求介绍 二、UVC介绍 三、解析 四、补丁修改 1、预览的限制主要存在于hal层和framework层 2、添加所需要的分辨率&#xff1a; 3、hal层修改 4、frameworks 5、备…

第九届清洁能源与发电技术国际学术会议(CEPGT 2024)

第九届清洁能源与发电技术国际学术会议&#xff08;CEPGT 2024&#xff09; 2024 9th International Conference on Clean Energy and Power Generation Technology (CEPGT 2024) 【早投稿早录用&#xff0c;享受早鸟优惠】 CEPGT 2024会议已上线至IEEE官网 第九届清洁能源…

15分钟学Go 第2天:安装Go环境

第2天&#xff1a;安装Go环境 1. 引言 在学习Go语言之前&#xff0c;首先需要配置好本地开发环境。本节将详细介绍如何在Windows 11上安装和配置Go语言环境&#xff0c;包括安装步骤、环境变量设置、VS Code配置与测试、以及常见问题解决方案。完成这些步骤后&#xff0c;你将…

Java项目-基于springboot框架的基于协同过滤算法商品推荐系统项目实战(附源码+文档)

作者&#xff1a;计算机学长阿伟 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、ElementUI等&#xff0c;“文末源码”。 开发运行环境 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBoot、Vue、Mybaits Plus、ELementUI工具&#xff1a;IDEA/…

Kettle9.4支持Clickhouse数据源插件开发以及性能测试

前言 最近业务这边有个指标需要用到大数据这边的列式数据库进行处理&#xff0c;由于kettle不支持clickhouse数据源驱动&#xff0c;这里查了一下网上的相关资料&#xff0c;发现了一些别人开发好的驱动包&#xff0c;下载下来后使用效果不尽人意。总结下来有以下几个问题&…

quic-go源码一---server启动

前言&#xff1a; 走马观花地看了RFC 9000:QUIC: A UDP-Based Multiplexed and Secure Transport&#xff0c; 感受不是那么直观&#xff0c;所以再来看看这个协议的golang语言实现&#xff1a;quic-go,加强学习。 https://quic-go.net/docs/quic/quic-go文档 本篇准备的代…

基于R语言机器学习方法在生态经济学领域中技术应用

近年来&#xff0c;人工智能领域已经取得突破性进展&#xff0c;对经济社会各个领域都产生了重大影响&#xff0c;结合了统计学、数据科学和计算机科学的机器学习是人工智能的主流方向之一&#xff0c;目前也在飞快的融入计量经济学研究。表面上机器学习通常使用大数据&#xf…