当前位置: 首页 > article >正文

C++类与对象进阶知识深度解析

目录

一、再谈构造函数

(一)构造函数体赋值

(二)初始化列表

(三)成员变量初始化顺序

(四)explicit关键字

二、static成员

(一)概念

(二)特性

(三)相关问题思考

三、友元

(一)友元函数

(二)友元类


一、再谈构造函数

(一)构造函数体赋值

在C++中,创建对象时,编译器会调用构造函数为对象的成员变量赋初始值。以 Date 类为例:


 

cppclass Date{public:Date(int year, int month, int day){_year = year;_month = month;_day = day;}private:int _year;int _month;int _day;};

这里看似是初始化,实则是赋值。真正的初始化只能进行一次,而构造函数体内可以多次赋值。比如先创建对象,再多次调用成员函数修改成员变量的值。

(二)初始化列表

初始化列表以冒号开始,后面跟着逗号分隔的成员变量初始化表达式。还是以 Date 类为例:

cppclass Date{public:Date(int year, int month, int day): _year(year), _month(month), _day(day){}private:int _year;int _month;int _day;};

使用初始化列表有诸多好处。首先,对于一些成员变量,如引用成员变量、 const 成员变量以及没有默认构造函数的自定义类型成员变量,必须使用初始化列表进行初始化。例如:


 

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

其次,使用初始化列表效率更高。因为对于自定义类型成员变量,即使在构造函数体中赋值,编译器也会先使用默认构造函数初始化,再进行赋值操作,而初始化列表可以直接调用合适的构造函数初始化。

(三)成员变量初始化顺序

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

cppclass A{public:A(int a): _a1(a), _a2(_a1){}void Print() {std::cout << _a1 << " " << _a2 << std::endl;}private:int _a2;int _a1;};int main() {A aa(1);aa.Print();return 0;}

这里先初始化 _a2 ,再初始化 _a1 ,所以输出结果可能不是预期的 1 1 ,而是 1 随机值 。

(四)explicit关键字

对于接收单个参数的构造函数,除了构造对象外,还具有类型转换的作用。但有时候我们不希望这种隐式类型转换发生,就可以使用 explicit 关键字。比如 Date 类:

cppclass Date{public:// 单参构造函数,没有使用explicit修饰,具有类型转换作用// explicit修饰构造函数,禁止类型转换,去掉explicit后,代码可以通过编译explicit Date(int year):_year(year){}// 虽然有多个参数,但是创建对象时后两个参数可以不传递,没有使用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对象进行赋值d1 = 2023; // 将1屏蔽掉,放开时则编译失败,因为explicit修饰构造函数,禁止了单参构造函数类型转换的作用}

使用 explicit 修饰后,就禁止了构造函数的隐式类型转换,提高了代码的可读性和安全性。

二、static成员

(一)概念

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

例如,要实现一个类来计算程序中创建了多少个类对象:


cppclass A{public:A() { ++_scount; }A(const A& t) { ++_scount; }~A() { --_scount; }static int GetACount() { return _scount; }private:static int _scount;};int A::_scount = 0;void TestA(){std::cout << A::GetACount() << std::endl;A a1, a2;A a3(a1);std::cout << A::GetACount() << std::endl;}

这里 _scount 是静态成员变量,记录对象个数, GetACount 是静态成员函数,用于获取对象个数。

(二)特性

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

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

3. 类静态成员既可用 类名::静态成员 或者 对象.静态成员 来访问。

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

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

(三)相关问题思考

1. 静态成员函数可以调用非静态成员函数吗?

答案是否定的。因为静态成员函数没有 this 指针,无法确定要操作哪个具体对象的非静态成员。

2. 非静态成员函数可以调用类的静态成员函数吗?

可以。因为静态成员函数是类共享的,非静态成员函数有 this 指针,可以通过类名或对象来调用静态成员函数。

三、友元

友元提供了一种突破封装的方式,在某些情况下能带来便利,但也会增加耦合度,破坏封装性,所以不宜多用。友元分为友元函数和友元类。

(一)友元函数

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

以 Date 类为例:


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

友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在类的内部声明。友元函数具有以下特点:

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

- 友元函数不能用 const 修饰。

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

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

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

(二)友元类

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

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

友元类有以下特性:

- 友元关系是单向的,不具有交换性。比如上述 Time 类和 Date 类,在 Time 类中声明 Date 类为其友元类,那么可以在 Date 类中直接访问 Time 类的私有成员变量,但想在 Time 类中访问 Date 类中私有的成员变量则不行。

- 友元关系不能传递。如果 B 是 A 的友元, C 是 B 的友元,则不能说明 C 是 A 的友元。

- 友元关系不能继承,在继承位置再给大家详细介绍。

通过对构造函数、 static 成员以及友元的深入剖析,我们对C++类与对象的知识有了更全面和深刻的理解。在实际编程中,合理运用这些特性可以编写出更高效、灵活且安全的代码。

相关文章:

C++类与对象进阶知识深度解析

目录 一、再谈构造函数 &#xff08;一&#xff09;构造函数体赋值 &#xff08;二&#xff09;初始化列表 &#xff08;三&#xff09;成员变量初始化顺序 &#xff08;四&#xff09;explicit关键字 二、static成员 &#xff08;一&#xff09;概念 &#xff08;二&am…...

BoostSearch搜索引擎项目 —— 测试用例设计 + web自动化测试代码

web自动化代码&#xff1a; https://gitee.com/chicken-c/boost-search/tree/master/AutoTest...

【Ansible自动化运维】一、初步了解,开启自动化运维之旅

在当今数字化时代&#xff0c;随着企业 IT 基础设施规模的不断扩大&#xff0c;传统的手工运维方式逐渐显得力不从心。自动化运维技术应运而生&#xff0c;其中 Ansible 凭借其简洁易用、功能强大的特点&#xff0c;成为众多运维工程师和开发人员的首选工具。本篇文章将从基础概…...

AI日报 - 2025年4月9日

&#x1f31f; 今日概览(60秒速览) ▎&#x1f916; AGI突破 | DeepSeek AI推出自我原则批判调优(SPCT)新方法 通过GRMs自我创建和批判原则&#xff0c;性能媲美671B参数大模型 ▎&#x1f4bc; 商业动向 | NVIDIA发布Llama-Nemotron-Ultra 253B模型 开放权重和训练数据&#x…...

2025年二级建造师考前冲刺题库

二建考前冲刺练习通常会涵盖考试的重点和高频考点&#xff0c;考生在做题过程中可以加深对这些知识点的理解和记忆&#xff0c;提高对重点知识的掌握程度。 建设工程法规及相关知识 1、单选题&#xff1a;关于建设工程中代理的说法&#xff0c;正确的是&#xff08; &#xf…...

蓝桥·20264-祝福语--找连续字串的长度

#include <iostream> using namespace std; int main() {// 请在此输入您的代码//最小字典序&#xff0c;一定是全a&#xff0c;找s的最长字串a,结果就是该字串长度加1&#xff08;t不能是s的子串&#xff09;//所以这道题就变成了&#xff0c;找s中字串a出现的长度strin…...

条件概率、概率乘法公式、全概率公式和贝叶斯 (Bayes) 公式

定义 设 P ( A ) > 0 P(A) > 0 P(A)>0&#xff0c;若在随机事件 A A A发生的条件下随机事件 B B B发生的概率记作 P ( B ∣ A ) P(B|A) P(B∣A)&#xff0c;定义 P ( B ∣ A ) P ( A B ) P ( A ) P(B|A) \frac{P(AB)}{P(A)} P(B∣A)P(A)P(AB)​ 则称 P ( B ∣ A ) …...

pdf转latex

Doc2X&#xff08;https://doc2x.noedgeai.com/&#xff09; Doc2X 是一个由 NoEdgeAI 提供的在线工具&#xff0c;主要用于将 PDF 文件&#xff08;尤其是学术论文、报告等文档&#xff09;转换为 LaTeX 格式。LaTeX 是一种高质量排版系统&#xff0c;广泛应用于学术界和出版…...

【Unity】Unity Transform缩放控制教程:实现3D模型缩放交互,支持按钮/鼠标/手势操作

【Unity 】Transform缩放控制教程&#xff1a;实现3D模型缩放交互&#xff0c;支持按钮/鼠标/手势操作 在Unity开发中&#xff0c;Transform组件承担着场景中物体的空间信息控制&#xff0c;包括位置、旋转和缩放。而缩放&#xff08;Scale&#xff09;操作&#xff0c;作为三…...

【Linux篇】缓冲区的工作原理:如何影响你程序的输入输出速度

从内存到磁盘&#xff1a;缓冲区如何提升文件I/O效率 一. 缓冲区1.1 什么是缓冲区1.2 为什么要引入缓冲区1.3 缓冲区类型1.4 FILE1.4.1 基本概念1.4.2 FILE 结构体的作用1.4.3 FILE 的工作机制 二. 最后 在程序开发中&#xff0c;缓冲区是一个经常被提及却不容易深入理解的概念…...

kotlin,Android,jetpack compose,日期时间设置

AI生成&#xff0c;调试出来学习&#xff0c;这些小组件会用了&#xff0c;就可以组合一个大点的程序了。 package com.example.mydatetimeimport android.app.AlertDialog import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.co…...

ASP.NET图书馆借阅系统(源码+lw+部署文档+讲解),源码可白嫖!

摘要 近些年来&#xff0c;随着科技的飞速发展&#xff0c;互联网的普及逐渐延伸到各行各业中&#xff0c;给人们生活带来了十分的便利&#xff0c;图书馆借阅系统利用计算机网络实现信息化管理&#xff0c;使图书信息、图书借阅、归还的管理发展和服务水平有显著提升。 本文拟…...

LeetCode算法题(Go语言实现)_35

题目 给你一棵根为 root 的二叉树&#xff0c;请你返回二叉树中好节点的数目。 「好节点」X 定义为&#xff1a;从根到该节点 X 所经过的节点中&#xff0c;没有任何节点的值大于 X 的值。 一、代码实现 func goodNodes(root *TreeNode) int {if root nil {return 0}return d…...

vi/vim常用快捷键

那么今天我们继续昨天没有介绍完的vi编辑器,来看看常用的一些快捷键,方便我们对文件的编辑. 1.拷贝当前行yy,拷贝当前行向下的5行5yy,并粘贴(输入p) 2.删除当前行dd,删除当前行向下的5行5d 3.在文件中查找某个单词[命令模式/关键字,回车查找,输入n就是查找下一个] ⭐️&…...

JVM核心机制:类加载×字节码引擎×垃圾回收机制

&#x1f680;前言 “为什么你的Spring应用启动慢&#xff1f;为什么GC总是突然卡顿&#xff1f;答案藏在JVM的核心机制里&#xff01; 本文将用全流程图解字节码案例&#xff0c;带你穿透三大核心机制&#xff1a; 类加载&#xff1a;双亲委派如何防止恶意代码入侵&#xff…...

opencv无法设置禁用RGB转换问题

树莓派连接摄像头,摄像头输出格式为YUYV(YUV422)。 通过执行 v4l2-ctl --list-formats --device/dev/video0 可以看的具体的摄像头的数据格式。 使用opencv获取视频流&#xff0c;通过cap.set(cv2.CAP_PROP_CONVERT_RGB, 0)设置禁用自动转换RGB格式&#xff0c;但是打印输出…...

k8s 1.30.6版本部署(使用canal插件)

#系统环境准备 参考 https://blog.csdn.net/dingzy1/article/details/147062698?spm1001.2014.3001.5501 #配置下载源 curl -fsSL https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.30/deb/Release.key |gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyri…...

GZ036区块链卷一 EtherStore合约漏洞详解

题目 pragma solidity >0.8.3;contract EtherStore {mapping(address > uint) public balances;function deposit() public payable {balances[msg.sender] msg.value;emit Balance(balances[msg.sender]);}function withdraw() public {uint bal balances[msg.sender…...

MCP+Blender创建电力塔

MCP&#xff08;Model Context Protocol&#xff09;与Blender的结合是当前AI与3D建模领域的热门技术&#xff0c;它通过协议化的方式让Claude等AI模型直接控制Blender&#xff0c;实现自动化3D建模。 1. 功能与原理 • 核心能力&#xff1a;用户通过自然语言指令&#xff08;…...

什么是RACI矩阵,应用在什么场景?

一、什么是RACI RACI矩阵是一种用于明确项目或任务中角色与责任的管理工具&#xff0c;通过定义不同人员在任务中的参与程度来避免职责不清的问题。以下是其核心要点&#xff1a; ‌RACI的含义‌ ● ‌R&#xff08;Responsible&#xff09;执行者‌&#xff1a;直接完成任务…...

Selenium自动化:玩转浏览器,搞定动态页面爬取

嘿&#xff0c;各位爬虫爱好者和自动化达人们&#xff01;是不是经常遇到这种情况&#xff1a;信心满满地写好爬虫&#xff0c;requests一把梭&#xff0c;结果抓下来的HTML里&#xff0c;想要的数据空空如也&#xff1f;定睛一看&#xff0c;原来数据是靠JavaScript动态加载出…...

QAI AppBuilder 快速上手(8): 图像修复应用实例2

LaMa-Dilated模型旨在通过扩张卷积技术实现高效的图像擦除和修复。该模型采用先进的卷积神经网络架构&#xff0c;能够处理复杂的图像输入&#xff0c;并填补图像中的缺失部分&#xff0c;使修复后的图像更加自然和逼真。LaMa-Dilated不仅在图像编辑领域表现出色&#xff0c;还…...

`ConstantPositionProperty` 的使用与应用

ConstantPositionProperty 的使用与应用 1. 什么是 ConstantPositionProperty&#xff1f; ConstantPositionProperty 是 Cesium 中用于表示实体位置的属性类。它表示一个实体在三维空间中的位置是固定的&#xff0c;不会随时间变化。与动态位置属性&#xff08;如 SampledPo…...

【计网】作业4

一. 单选题&#xff08;共22题&#xff0c;64分&#xff09; 1. (单选题)主机甲采用停止-等待协议向主机乙发送数据&#xff0c;数据传输速率是4kb/s&#xff0c;单向传播时延为30ms&#xff0c;忽略确认帧的发送时延。当信道利用率等于80%时&#xff0c;数据帧的长度为&#…...

MPDrive:利用基于标记的提示学习提高自动驾驶的空间理解能力

25年4月来自南方科技大学、百度、英国 KCL和琶洲实验室&#xff08;广东 AI 和数字经济实验室&#xff09;的论文“MPDrive: Improving Spatial Understanding with Marker-Based Prompt Learning for Autonomous Driving”。 自动驾驶视觉问答&#xff08;AD-VQA&#xff09;…...

QTSql全解析:从连接到查询的数据库集成指南

概览 与数据库的有效集成是确保数据管理效率和应用性能的关键&#xff0c;Qt框架就提供了强大的QtSql模块&#xff0c;使得开发者能够轻松地进行数据库操作&#xff0c;包括连接、查询执行以及结果处理等 一、引入QtSql模块 首先&#xff0c;需要在项目中引入QtSql模块&…...

FreeRTOS临界区

在FreeRTOS中&#xff0c;临界区通过关闭可管理的中断来保护共享资源&#xff0c;具体关闭的中断层级由configMAX_SYSCALL_INTERRUPT_PRIORITY宏定义决定。以下是关键点解析&#xff1a; 中断优先级分类&#xff1a; 高优先级中断&#xff1a;数值低于configMAX_SYSCALL_INTERR…...

【学习笔记】HTTP和HTTPS的核心区别及工作原理

一、基础概念 HTTP&#xff08;超文本传输协议&#xff09;&#xff1a;明文传输数据&#xff0c;默认端口80&#xff0c;容易被窃听或篡改。 HTTPS&#xff08;HTTP SSL/TLS&#xff09;&#xff1a;通过加密传输数据&#xff0c;默认端口443&#xff0c;保障安全性。 二、…...

Dubbo的简单介绍

Dubbo的简单介绍 Dubbo 是一个高性能的 Java RPC 框架&#xff0c;最初由阿里巴巴开发&#xff0c;用于构建分布式服务。它主要用于提供服务间的通信&#xff0c;支持高效的远程调用和服务治理&#xff0c;常用于大规模分布式系统中。Dubbo 提供了以下几个核心功能&#xff1a…...

7.2 重复推送(每日、每周等)

1. 核心方法 使用 UNCalendarNotificationTrigger 的 dateMatching 参数配置日历组件&#xff08;DateComponents&#xff09;&#xff0c;结合 repeats: true 实现周期性触发。 2. 不同频率的重复推送配置 2.1 每日重复 每天固定时间触发&#xff08;如上午 10:00&#xff…...