C++ | 面向对象 | 类
👻类
👾语法格式
class className{Access specifiers: // 访问权限DataType variable; // 变量returnType functions() { } // 方法
};
👾访问权限
class className {public:// 公有成员protected:// 受保护成员private:// 私有成员
};
👽公有成员 public
公有成员在类外部可访问,可不使用任何成员函数来设置和获取公有变量的值
class Line {public:double length;void setLength(double len);double getLength(void);
};
double Line::getLength(void) { return length ; }
void Line::setLength(double len) { length = len; }...
Line line;
// 使用成员变量(正确,因为 length 公有)
line.length = 10.0;
cout << line.length <<endl;
// 使用成员函数
line.setLength(6.0);
cout << line.getLength() <<endl;
👽私有成员 private
私有成员在类外部不可访问,不可查看,只有类和友元函数可以访问私有成员。没有使用任何访问修饰符默认私有。
class Box {public:double length;void setWidth(double wid);double getWidth(void);private:double width;
};
double Box::getWidth(void) { return width; }
void Box::setWidth( double wid ) { width = wid; }...
Box box;
// box.width = 10.0; // [Error] 'double Box::width' is private
box.setWidth(10.0); // 使用成员函数设置宽度
cout << box.getWidth() <<endl;
👽受保护成员 protected
受保护成员与私有成员相似,但有一点不同,受保护成员在**派生类(即子类)**中是可访问的。
/* 基类 */
class Box {protected:double width;
};/* 派生类 */
class SmallBox: Box { public:void setSmallWidth(double wid);double getSmallWidth();
};
double SmallBox::getSmallWidth() { return width; }
void SmallBox::setSmallWidth(double wid) { width = wid; }...
SmallBox box;
box.setSmallWidth(5.0);
cout << box.getSmallWidth() << endl;
👻类成员函数
👾语法格式
-
定义在类定义内部
class className{returnType functions(parameter list) { ... } };
-
单独使用范围解析运算符
::
定义class className{returnType functions(parameter list); }; returnType class_name::functions(parameter list){ ... }
👾示例代码
-
定义在类定义内部
class Box {public:double length; // 长度double breadth; // 宽度double height; // 高度double getVolume() { return length * breadth * height; } };
-
单独使用范围解析运算符
::
定义class Box {public:double length; // 长度double breadth; // 宽度double height; // 高度double getVolume(); };double Box::getVolume() { return length * breadth * height; }
👻类构造函数
- 类构造函数在每次创建类的新对象时执行。
- 构造函数的名称与类的名称是完全相同的,不返回任何类型。
- 构造函数可用于为某些成员变量设置初始值。
👾无参构造函数
👽语法格式
class className{className() { ... }
};
👽示例代码
class Line {public:Line() { cout << "Object is being created" << endl; }private:double length;
};...
Line line; // 输出:Object is being created
👾带参构造函数
👽语法格式
class className{className(parameter list) { ... }
};
👽示例代码
class Line {public:Line(double len) {length = len;cout << "Object is being created" << endl;}private:double length;
};...
Line line; // 输出:Object is being created
👾初始化列表构造函数
👽语法格式
类有多个字段 A、B、C 等需要进行初始化:
class className{className(int a,int b,int c): A(a), B(b), C(c) { ... }
};
👽示例代码
class Line {public:Line(double len): length(len) { cout << "Object is being created" << endl; }private:double length;
};...
Line line; // 输出:Object is being created
等同语法:
Line(double len) {length = len;cout << "Object is being created" << endl;
}
注意:初始化类成员时,是按声明的顺序初始化,而不是按初始化列表的顺序初始化,即:
class Base {public:// 按照 A -> B -> C 的顺序初始化int A;int B;int C;// 而不是按照 C -> B -> A 的顺序初始化Base(int a, int b, int c): C(c), B(b), A(a) {} };
👻类析构函数
- 类析构函数在每次删除所创建的对象时执行。
- 析构函数的名称与类的名称是完全相同的,在前面加
波浪号(~)
作为前缀,不返回任何值,不能带有任何参数。 - 析构函数有助于在跳出程序(比如关闭文件、释放内存等)前释放资源。
👾语法格式
类有多个字段 A、B、C 等需要进行初始化:
class className{~className() { ... }
};
👾示例代码
class Line {public:Line() { cout << "Object created" << endl; } // 构造函数声明~Line() { cout << "Object deleted" << endl; } // 析构函数声明
};...
Line line;
一个类内可以有多个构造函数(相当于重载构造函数),只有一个析构函数
class Matrix {public:Matrix(int row, int col); //普通构造函数Matrix(const Matrix& matrix); //拷贝构造函数Matrix(); //构造空矩阵的构造函数~Matrix(); };
👻类拷贝构造函数
👾语法结构
class className{// obj是对象引用,用于初始化另一个对象className (const className &obj) { }
};
-
参数
obj
—— 本类的引用-
const
类型引用 —— 既能以常量对象(初始化后值不改变的对象)作为参数,也能以非常量对象作为参数初始化其他对象 -
非
const
类型引用 —— 一般不使用
-
👾被调用情况
-
情况1:用一个对象初始化同类的另一个对象时,调用被初始化的对象的拷贝构造函数
Base a2(a1); Base a2 = a1;
class Base {public:int num;// 一般构造函数Base(int n) {num = n;cout << "General Constructor called" << endl;}// 拷贝构造函数Base(const Base& a) {num = a.num;cout << "Copy Constructor called" << endl;} };...// 只调用a1的一般构造函数,输出 General Constructor called Base a1(1); // 只调用a2的拷贝构造函数,输出 Copy Constructor called Base a2(a1); Base a2 = a1; // 不调用 a2 = a1;
注意,
Base a2 = a1;
是初始化语句,不是赋值语句。赋值语句的等号左边是一个早已有定义的变量,不会引发复制构造函数的调用,
Base a1(1); // 调用a1的一般构造函数 Base a2(a1); // 调用a2的拷贝构造函数 a2 = a1; // 不调用,因为 a2 早已生成且初始化,不会引发拷贝构造函数
只会调用被初始化的对象的拷贝构造函数,不会调用其一般构造函数
-
情况2:函数参数是类的对象,当函数调用时,调用对象的拷贝构造函数
class Base {public:// 一般构造函数Base() { cout << "General Constructor called" << endl; };// 拷贝构造函数Base(Base& a) { cout << "Copy constructor called" << endl; } }; void Function(Base a) {}...Base a; // 调用a的一般构造函数,输出 General Constructor called Function(a); // 调用a的拷贝构造函数,输出 Copy constructor called
- 以对象作为形参,函数被调用时,生成形参要用拷贝构造函数,会带来时间开销
- 用对象的引用作为形参,无时间开销,但有一定的风险,因为如果形参的值发生改变,实参值也会改变
如果要确保实参值不改变,又希望避免拷贝构造函数的开销,解决办法是将形参声明为对象的
const
引用:void Function(const Base &a){... }
-
情况3:函数返回值是类的对象,当函数返回时,调用对象的拷贝构造函数
class Base {public:int num;// 一般构造函数Base(int n) {num = n;cout << "General Constructor called" << endl;}// 拷贝构造函数Base(const Base& a) {num = a.num;cout << "Copy constructor called" << endl;} };Base Func() {Base a(4); // 调用一般构造函数,输出 General Constructor calledreturn a; }...int a = Func().num; // 调用拷贝构造函数,输出 Copy constructor called
有些编译器出于程序执行效率的考虑,编译时进行优化,函数返回值对象不用拷贝构造函数,不符合C++标准
👾深拷贝和浅拷贝
👽浅拷贝
- 使用情况:基本类型数据、简单对象
- 原理:按位复制内存
// 基本类型数据
int a = 10;
int b = a;
// 简单对象
class Base {public:Base(): m_a(0), m_b(0) { }Base(int a, int b): m_a(a), m_b(b) { }private:int m_a;int m_b;
};Base obj1(10, 20);
Base obj2 = obj1;
👽深拷贝
- 使用情况:
- 持有其它资源的类(如动态分配的内存、指向其他数据的指针)
- 标准模板库(STL)中 string、vector、stack 等
- 创建对象时进行一些预处理工作,比如统计创建过的对象的数目、记录对象创建的时间等
- 原理:显式定义拷贝构造函数
- 过程:
- 会将原有对象的所有成员变量拷贝给新对象
- 会为新对象再分配一块内存,并将原有对象所持有的内存也拷贝过来
- 结果:原有对象和新对象所持有的动态内存相互独立,更改一个对象的数据不影响另一个对象
// 持有其它资源的类(如动态分配的内存、指向其他数据的指针)
#include <cstdlib>
#include <iostream>
using namespace std;class Array {public:Array(const int len) {m_len = len;m_p = (int*)calloc(m_len, sizeof(int));}Array(const Array& arr) {this->m_len = arr.m_len;this->m_p = (int*)calloc(this->m_len, sizeof(int));memcpy(this->m_p, arr.m_p, m_len * sizeof(int));}~Array() { free(m_p); }int operator[](int i) const { return m_p[i]; }int& operator[](int i) { return m_p[i]; }int length() const { return m_len; }private:int m_len;int* m_p;
};void printArray(const Array& arr) {int len = arr.length();for(int i = 0; i < len; i++) { if(i == len - 1) { cout << arr[i] << endl; } else { cout << arr[i] << ", "; } }
}...int main() {Array arr1(10);for(int i = 0; i < 10; i++)arr1[i] = i;Array arr2 = arr1;arr2[5] = 100;arr2[3] = 29;printArray(arr1); // 输出:0, 1, 2, 3, 4, 5, 6, 7, 8, 9printArray(arr2); // 输出:0, 1, 2, 29, 4, 100, 6, 7, 8, 9
}
// 创建对象时进行一些预处理工作
#include <iostream>
#include <ctime>
#include <windows.h>
using namespace std;class Base {public:Base(int a = 0, int b = 0) {m_a = a;m_b = b;m_count++;m_time = time(nullptr);}Base(const Base& obj) {this->m_a = obj.m_a;this->m_b = obj.m_b;this->m_count++;this->m_time = time(nullptr);}static int getCount() { return m_count; }time_t getTime() const { return m_time; }private:int m_a;int m_b;time_t m_time; //对象创建时间static int m_count; //创建过的对象的数目
};int Base::m_count = 0;...int main() {Base obj1(10, 20);cout << "obj1: count = " << obj1.getCount() << ", time = " << obj1.getTime() << endl;// 输出:obj1: count = 1, time = 1740055359Sleep(3000);Base obj2 = obj1;cout << "obj2: count = " << obj2.getCount() << ", time = " << obj2.getTime() << endl;// 输出:obj2: count = 2, time = 1740055362return 0;
}
👻类静态成员
👾类静态成员变量
👽声明
使用 关键字 static
把类成员声明为静态
class Box {public:static int objectCount; // 声明静态变量Box() { objectCount++; } // 每次创建对象时调用构造函数,静态变量值加 1
};
无论创建多少个类的对象,静态成员只有一个副本,在类的所有对象中是共享的。
👽定义
在类外部通过 范围解析运算符 ::
定义静态变量
class Box {public:static int objectCount; // 声明静态变量Box() { objectCount++; }
};
// 仅定义却不初始化 类静态成员
int Box::objectCount;
无论是否初始化,必须定义,否则报错:
(.rdata$.refptr._ZN3Box11objectCountE[.refptr._ZN3Box11objectCountE]+0x0): undefined reference to `Box::objectCount'
👽初始化
// 定义+初始化 类静态成员
int Box::objectCount = 0;
若不初始化,则在创建第一个对象时所有静态数据初始化为零。
👽访问
- 使用 范围解析运算符
::
访问类静态变量
Box box1(); // 声明 box1
Box box2(); // 声明 box2
cout << "创建对象总数: " << Box::objectCount << endl;
👾类静态成员函数
👽声明定义
- 使用 关键字
static
把类成员声明为静态
class Box {public:static int objectCount; // 声明静态变量Box() { objectCount++; }static int getCount() { // 声明定义静态函数return objectCount;}
};
- 普通成员函数有
this
指针,可以访问类中的任意成员- 静态成员函数没有
this
指针,只能访问静态成员变量、其他静态成员函数、类外部的其他函数
👽使用
- 使用 范围解析运算符
::
访问类静态变量
cout << "创建对象总数: " << Box::getCount() << endl; // 对象不存在时 也能被调用
Box box1(); // 声明 box1
Box box2(); // 声明 box2
cout << "创建对象总数: " << Box::getCount() << endl;
静态成员函数即使 类对象不存在 也能被调用
👻友元
👾友元函数
- 类的友元函数定义在类外部,但有权访问类的私有成员、保护成员
- 尽管友元函数的原型在类的定义中出现,但友元函数不是成员函数
👽声明
使用 关键字 friend
把函数声明为友元函数
class Box {double width;public:Box(double w): width(w) {}friend void printWidth(Box box); // 在函数前使用关键字 friend
};
👽定义
class Box {double width;public:Box(double w): width(w) {}friend void printWidth(Box box);
};/* printWidth() 不是任何类的成员函数,但因为它是 Box 的友元,可直接访问该类的任何成员 */
void printWidth(Box box) { cout << "Width of box : " << box.width <<endl;}
👽使用
Box box;
box.setWidth(10.0);
printWidth(box); // 使用友元函数访问Box中的私有成员
👾友元类
👽声明定义
class Box {public:Box(double w): width(w) {}friend class BigBox;private:double width;
};/* BigBox是Box的友元类,它可以直接访问Box类的任何成员 */
class BigBox {public :void printWidth(Box& box) { cout << "Width of box : " << box.width << endl; }
};
👽使用
Box box(10.0);
BigBox big;
big.printWidth(box); // 使用友元类中的方法访问Box中的私有成员
👻 this 指针
this
指针是一个特殊的指针,它指向当前对象的实例,每一个对象都能通过this
指针来访问自己的地址。- 当一个对象的成员函数被调用时,编译器会隐式地传递该对象的地址作为
this
指针。 - 友元函数没有
this
指针,因为友元不是类的成员
class MyClass {private:int value;public:// 可以明确地告诉编译器想访问当前对象的成员变量,而不是函数参数或局部变量,避免命名冲突void setValue(int value) { this->value = value; } void getValue() { return this->value; }
};...MyClass obj;
obj.setValue(42);
int value = obj.getValue();
相关文章:
C++ | 面向对象 | 类
👻类 👾语法格式 class className{Access specifiers: // 访问权限DataType variable; // 变量returnType functions() { } // 方法 };👾访问权限 class className {public:// 公有成员protected:// 受保护成员private:// 私有成员 }…...

leetcode:2164. 对奇偶下标分别排序(python3解法)
难度:简单 给你一个下标从 0 开始的整数数组 nums 。根据下述规则重排 nums 中的值: 按 非递增 顺序排列 nums 奇数下标 上的所有值。 举个例子,如果排序前 nums [4,1,2,3] ,对奇数下标的值排序后变为 [4,3,2,1] 。奇数下标 1 和…...
Visionpro cogToolBlockEditV2.Refresh()
在 C# 中使用 cogToolBlockEditV2.Refresh() 方法主要用于刷新 CogToolBlockEditV2 控件的显示状态,适用于动态更新界面或重新加载工具块(ToolBlock)的场景。以下是具体说明和典型应用场景。 基本作用 刷新控件显示:当修改了与 C…...
Apache Spark中的依赖关系与任务调度机制解析
Apache Spark中的依赖关系与任务调度机制解析 在Spark的分布式计算框架中,RDD(弹性分布式数据集)的依赖关系是理解任务调度、性能优化及容错机制的关键。宽依赖(Wide Dependency)与窄依赖(Narrow Dependency)作为两种核心依赖类型,直接影响Stage划分、Shuffle操作及容…...

网络基础III
目录 一、网络层 1.1IP协议 1.2网段划分(🔺) 1.3特殊的ip地址 1.4ip地址的数量限制 1.5私有ip和公网ip 1.6路由 二、数据链路层 2.1认识以太网 2.2以太网帧格式 2.3认识mac地址 2.4mac地址和ip地址 2.5认识MTU 2.6MTU对IP协议的…...

【SpringBoot】自动配置原理与自定义启动器
Spring Boot 自动配置原理与自定义启动器 目录标题 Spring Boot 自动配置原理与自定义启动器摘要1. 引言2. Spring Boot自动配置原理分析2.1 自动配置的核心流程2.2 核心注解与配置文件解析2.2.1 EnableAutoConfiguration2.2.2 spring.factories 文件 2.3 自动配置类剖析2.4 配…...
Element实现el-dialog弹框移动、全屏功能
1、在Vue项目中src/utils目录中创建dialog.js,用来定义draggable-dialog; import Vue from vue Vue.directive(draggable-dialog, { // 属性名称draggable-dialog,前面加v- 使用bind(el, binding, vnode) {const dialogHeaderEl el.querySe…...
Ubuntu 下 nginx-1.24.0 源码分析 - ngx_init_cycle 函数 - 详解(11)
详解(11) 初始化配置解析上下文 senv environ;ngx_memzero(&conf, sizeof(ngx_conf_t));/* STUB: init array ? */conf.args ngx_array_create(pool, 10, sizeof(ngx_str_t));if (conf.args NULL) {ngx_destroy_pool(pool);return NULL;}conf.te…...

千峰React:案例一
做这个案例捏 因为需要用到样式,所以创建一个样式文件: //29_实战.module.css .active{text-decoration:line-through } 然后创建jsx文件,修改main文件:导入Todos,写入Todos组件 import { StrictMode } from react …...
部署Joplin私有云服务器postgres版-docker compose
我曾经使用过一段时间 Joplin,官方版本是收费的,而我更倾向于将数据掌握在自己手中。因此,在多次权衡后,我决定自己搭建 Joplin 服务器并进行尝试。 个人搭建的版本与数据库直连,下面是使用 Docker Compose 配置数据库…...

rust学习笔记6-数组练习704. 二分查找
上次说到rust所有权看看它和其他语言比有什么优势,就以python为例 # Python3 def test():a [1, 3, -4, 7, 9]print(a[4])b a # 所有权没有发生转移del b[4]print(a[4]) # 由于b做了删除,导致a再度访问报数组越界if __name__ __main__:test() 运行结…...

Jsmoke-一款强大的js检测工具,浏览器部署即用,使用方便且高效
目录标题 Jsmoke 🚬🚬 by Yn8rt使用方式界面预览功能特性支持的敏感信息类型 Jsmoke 🚬🚬 by Yn8rt 该插件由 Yn8rt师傅 开发,插件可以理解为主动版的hae和apifinder,因为其中的大多数规则我都引用了&a…...

PyCharm中通过命令行执行`pip`命令下载到哪里了:虚拟环境目录下
PyCharm中通过命令行执行pip命令下载到哪里了:虚拟环境目录下 在PyCharm中通过命令行执行pip命令安装工具包,包的下载位置取决于多种因素 虚拟环境 如果项目使用了虚拟环境(通常是推荐的做法): Windows:虚拟环境通常位于项目目录下的.venv文件夹(默认情况)或你指定…...

Spring Boot操作MaxComputer(保姆级教程)
目录 引言 一、引入依赖 二、配置文件 application.properties(信息用自己的奥) 三、实体类User.java 四、UserController 五、UserService 六、UserDao 七、UserDao.xml 八、postman 访问,成功查询数据 附件(修改和删除数据) 引言…...

Spring的构造注入
1.开发步骤2.构造方法的重载 2.1参数个数不同2.2构造参数个数相同时 3.注入总结 注入:通过Spring的配置文件,为成员变量赋值 Set注入:Spring调用Set方法,通过配置文件,为成员变量赋值 构造注入:Spring调用…...

服务器IPMI用户名、密码批量检查
背景 大规模服务器部署的时候,少不了较多的网管和监测平台,这些平台会去监控服务器的性能、硬件等指标参数,为了便于管理和控制,则需要给服务器IPMI带外管理添加较多的用户,这就需要对较多的服务器检查所对应的IPMI用…...

管理后台环境配置
后端配置及启动 a. 软件安装 1. Java sdk 1.8 2. maven 3.6 3. intellij IDEA 2024 4. Visual C Redistributable 5. mongodb 7.0 6. mysql 8.0 双击安装:mysql-installer-community-8.0.41.0.msi 版本选择:Full,包括服务器和客户端 …...

element-ui infiniteScroll 组件源码分享
简单分享 infiniteScroll 组件源码,主要有以下四个方面: 1、infiniteScroll 页面结构。 2、infiniteScroll 组件属性。 3、组件内部的方法。 4、存在的问题。 一、infiniteScroll 页面结构: 二、页面属性。 2.1 infinite-scroll-disab…...

Pany-v2:LFI漏洞探测与敏感文件(私钥窃取/其他)自动探测工具
地址:https://github.com/MartinxMax/pany 关于Pany-v2 Pany-v2 是一款 LFI(本地文件包含)漏洞探测工具,具备自动识别敏感文件的能力。它能够利用 LFI 漏洞检测并提取 id_rsa 私钥、系统密码文件以及其他可能导致安全风险的敏感信息。该工具…...

供应链管理系统--升鲜宝门店收银系统功能解析,登录、主界面、会员 UI 设计图(一)
供应链管理系统--升鲜宝门店收银系统功能解析,登录、主界面 会员 UI 设计图(一)...

Chapter03-Authentication vulnerabilities
文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...
OpenLayers 可视化之热力图
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 热力图(Heatmap)又叫热点图,是一种通过特殊高亮显示事物密度分布、变化趋势的数据可视化技术。采用颜色的深浅来显示…...
Ubuntu系统下交叉编译openssl
一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机:Ubuntu 20.04.6 LTSHost:ARM32位交叉编译器:arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...
逻辑回归:给不确定性划界的分类大师
想象你是一名医生。面对患者的检查报告(肿瘤大小、血液指标),你需要做出一个**决定性判断**:恶性还是良性?这种“非黑即白”的抉择,正是**逻辑回归(Logistic Regression)** 的战场&a…...

循环冗余码校验CRC码 算法步骤+详细实例计算
通信过程:(白话解释) 我们将原始待发送的消息称为 M M M,依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)(意思就是 G ( x ) G(x) G(x) 是已知的)࿰…...

cf2117E
原题链接:https://codeforces.com/contest/2117/problem/E 题目背景: 给定两个数组a,b,可以执行多次以下操作:选择 i (1 < i < n - 1),并设置 或,也可以在执行上述操作前执行一次删除任意 和 。求…...

学校时钟系统,标准考场时钟系统,AI亮相2025高考,赛思时钟系统为教育公平筑起“精准防线”
2025年#高考 将在近日拉开帷幕,#AI 监考一度冲上热搜。当AI深度融入高考,#时间同步 不再是辅助功能,而是决定AI监考系统成败的“生命线”。 AI亮相2025高考,40种异常行为0.5秒精准识别 2025年高考即将拉开帷幕,江西、…...
基于Java Swing的电子通讯录设计与实现:附系统托盘功能代码详解
JAVASQL电子通讯录带系统托盘 一、系统概述 本电子通讯录系统采用Java Swing开发桌面应用,结合SQLite数据库实现联系人管理功能,并集成系统托盘功能提升用户体验。系统支持联系人的增删改查、分组管理、搜索过滤等功能,同时可以最小化到系统…...
go 里面的指针
指针 在 Go 中,指针(pointer)是一个变量的内存地址,就像 C 语言那样: a : 10 p : &a // p 是一个指向 a 的指针 fmt.Println(*p) // 输出 10,通过指针解引用• &a 表示获取变量 a 的地址 p 表示…...
git: early EOF
macOS报错: Initialized empty Git repository in /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/.git/ remote: Enumerating objects: 2691797, done. remote: Counting objects: 100% (1760/1760), done. remote: Compressing objects: 100% (636/636…...