【C++类和对象(中)】—— 我与C++的不解之缘(四)

news/2024/9/11 4:04:06/ 标签: c++, 开发语言

前言:

接下来进行类和对象中的学习,了解类和对象的默认成员函数

一、类和对象默认成员函数

        默认成员函数就是用户没有显示实现,编译器会自动生成的成员函数。

一个类,我们不显示实现的情况下,编译器就会默认生成一下留个默认成员函数。

        这里前4个(构造函数析构函数拷贝构造赋值重载)是重难点。

C++11以后还会增加两个默认成员函数,移动构造移动赋值

默认成员函数十分重要,从以下两个方面去深入了解:

  1. 我们不写时,编译器默认生成的函数行为是什么,是否满足我们的需求
  2. 编译器默认生成的函数不满足我们的需求,我们需要直接实现,那么如何自己实现呢?

        1.1、构造函数

        构造函数,是特殊的成员函数;这里需要注意,虽然名字叫做构造函数,但是构造函数的主要任务不是开辟空间创建对象(我们经常使用的局部对象是栈帧创建时,空间就已经开辟 好了),而是对象实例化时初始化对象

        这里构造函数本质上是替代实现的Stack和Data类中所写的 Init 函数,构造函数自动调用这一特点就完美替代了 Init 函数

1.1.1、构造函数的特点

构造函数的特点如下:

1、函数名和类名相同。

2、无返回值(返回值不需要写,void也不需要)。

3、对象实例化时系统会自动调用对应的构造函数。

4、构造函数可以重载

5、如果类没有显示定义构造函数,C++编译器会自动生成一个无参的默认构造函数;如果显示写了构造函数,编译器就不会再生成。

6、无参构造函数、全缺省构造函数、我们不写时编译器默认生成的构造函数,这三个都叫做默认构造函数。

7、我们不写,编译器默认生成的构造函数,对内置类型成员变量的初始化没有要求(是否初始看编译器);对于自定义类型成员变量,要求调用这个成员函数的默认构造函数初始化(如果这个成员变量没有默认构造函数,就会报错(这里要初始化这个成员变量,需要使用初始化列表来解决,后面会学习到))。

1.1.2、构造函数

        这里来看一下构造函数的前几个特点。

首先就是,构造函数的函数名和类名相同而且无返回值(不需要写返回值)

class Data
{
public:Data(){_year = 1;_month = 1;_day = 1;}private:int _year;int _month;int _day;};

        这里Data类里面的Data函数就是显示实现的构造函数(显示实现了构造函数,编译器就不会默认生成);

再来看,构造函数可以重载,我们就可以这样写:

class Data
{
public:Data(){_year = 1;_month = 1;_day = 1;}Data(int year, int month, int day){_year = year;_month = month;_day = day;}private:int _year;int _month;int _day;};

        这里两个构造函数就形成了重载,再创建对象时,不给参数就会调用第一个构造函数,给参数就会调用第二个参数。

最后,来看对象实例化时会自动构造函数:

#include<iostream>
using namespace std;
class Data
{
public:Data(){cout << "Data()" << endl;_year = 1;_month = 1;_day = 1;}Data(int year, int month, int day){cout << "Data(int year, int month, int day)" << endl;_year = year;_month = month;_day = day;}private:int _year;int _month;int _day;};
int main()
{Data d1;Data d2(2006, 7, 20);return 0;
}

1.1.3、默认构造函数

默认构造函数有三种:

        无参构造函数全缺省构造函数和我们不写时编译器默认生成的构造函数

这三个函数有且只有一个存在(不能同时存在);

        这里虽然无参构造函数和全缺省构造函数形成函数重载,但是在函数调用时会存在歧义:

#include<iostream>
using namespace std;
class Data
{
public:Data(){cout << "Data()" << endl;_year = 1;_month = 1;_day = 1;}Data(int year = 1, int month = 1, int day = 1){cout << "Data(int year, int month, int day)" << endl;_year = year;_month = month;_day = day;}private:int _year;int _month;int _day;};
int main()
{Data d1;return 0;
}

这里总结一下,编译传实参就可以调用的构造就是默认构造。

1.1.4、编译器默认生成的默认构造函数        

        编译器默认生成的构造函数,对于内置类型(整型,浮点型,字符类型,指针等)初始化没有要求,可能会初始化,也可能不做任何处理;对于自定义类型成员变量初始化会调用这个成员变量的默认构造函数(如果不存在默认构造就报错)。

        所以,大多情况下我们都需要自己实现构造函数。

        1.2、析构函数

        析构函数与构造函数的功能相反,析构函数不是完成对象本身的销毁(局部对象是存在栈帧的,函数结束栈帧就销毁了,局部对象就自动释放了);C++规定在销毁时会自动调用析构函数,完成对像中资源的清理释放工作。

        相关函数的功能类比之前 Stack 栈实现的DesTroy 销毁功能,对申请资源进行释放。

1.2.1、析构函数特点

1、析构函数名是在类名前面加上字符 ~

2、无参数返回值(与构造函数一样,不需要加void)。

3、一个类只能有一个析构函数,如果没有显示定义,系统就会自动生成默认的析构函数。

4、对象生命周期结束时,系统就会自动调用析构函数。

5、与构造函数类似,我们不显示写,编译器默认生成的对内置类型不做处理,自定义类型就会调用它的析构函数。

6、这里需要注意,我们显示写了析构函数,对于自定义类型也会调用它的析构函数(也就是说,无论说明情况下,自定义类型都会自动调用析构函数。

7、如果类没有申请资源,析构函数可以不写,直接使用编译器生成的默认析构函数,就比如Data(日期类);如果默认生成的析构就满足我们的需求,不用写,比如MyQueue(用两个栈实现的队列);如果有资源申请,一定要自己写析构,否则就会造成资源泄漏,比如Stack(栈)。

8、一个局部域的多个对象,C++ 规定后定义的先调用析构

1.2.2、析构函数

自己实现析构函数,这里拿栈Stack类来举例:

class Stack
{
public://构造函数Stack(int capacity = 4){cout << "Stack" << endl;_arr = (int*)malloc(sizeof(int) * capacity);if (_arr == NULL){perror("malloc fail");return;}_capacity = capacity;_top = 0;}//析构函数~Stack(){cout << "~Stack" << endl;if (_arr)free(_arr);_arr = nullptr;_capacity = _top = 0;}
private:int* _arr;int _top;int _capacity;
};

        这里,对象生命周期结束时会自动调用析构函数,看一下释放真的调用了?

int main()
{Stack st;return 0;
}

1.2.3、自定义类型自动调用其析构函数

        对于自定义类型,无论我们写函数不写析构,都会自动调用其析构函数。

class Stack
{
public://构造函数Stack(int capacity = 4){cout << "Stack" << endl;_arr = (int*)malloc(sizeof(int) * capacity);if (_arr == NULL){perror("malloc fail");return;}_capacity = capacity;_top = 0;}//析构函数~Stack(){cout << "~Stack" << endl;if (_arr)free(_arr);_arr = nullptr;_capacity = _top = 0;}
private:int* _arr;int _top;int _capacity;
};
class MyQueue
{
public:private:Stack pushst;Stack popst;
};
int main()
{MyQueue mq;return 0;
}

        

        这里可以看到,自定义类型构造和析构都调用了它的构造函数和析构函数。

        1.3、拷贝构造函数

        如果构造函数的第一个参数是自身类类型的引用,且任何额外的参数都有默认值,则此构造函数也叫做拷贝构造函数(也就是拷贝构造函数是特殊的构造函数)。

1.3.1、拷贝构造的特点

1、拷贝构造函数是构造函数的一个重载。

2、C++规定,自定义类的对象进行拷贝行为必须调用拷贝构造,所以这里自定义类型传值传参和传值返回都会调用拷贝构造完成。

3、拷贝构造的第一个参数必须是类类型对象的引用,使用传值方式编译器直接报错,因为语法逻辑上会引发无穷递归。

4、如果未显示定义拷贝构造,编译器会自动生成拷贝构造函数;

5、  像Date这样的类成员变量全是内置类型且没有指向什么资源,编译器⾃动⽣成的拷⻉构造就可以完 成需要的拷⻉,所以不需要我们显⽰实现拷⻉构造。

        像Stack这样的类,虽然也都是内置类型,但 是_a指向了资源,编译器⾃动⽣成的拷⻉构造完成的值拷⻉/浅拷⻉不符合我们的需求,所以需要我们⾃⼰实现深拷⻉(对指向的资源也进⾏拷⻉)。

        像MyQueue这样的类型内部主要是⾃定义类型 Stack成员,编译器⾃动⽣成的拷⻉构造会调⽤Stack的拷⻉构造,也不需要我们显⽰实现

MyQueue的拷⻉构造。
6、    传值返回会产⽣⼀个临时对象调⽤拷⻉构造,传值引⽤返回,返回的是返回对象的别名(引⽤),没有产⽣拷⻉。但是如果返回对象是⼀个当前函数局部域的局部对象,函数结束就销毁了,那么使⽤ 引⽤返回是有问题的,这时的引⽤相当于⼀个野引⽤,类似⼀个野指针⼀样。传引⽤返回可以减少 拷⻉,但是⼀定要确保返回对象,在当前函数结束后还在,才能⽤引⽤返回。

1.3.2、拷贝构造参数

        C++规定自定义类型对象拷贝时必须调用拷贝构造:

class Data
{
public://构造Data(int year = 1 , int month = 1, int day = 1){ cout << "Data(int year, int month, int day)" << endl;_year = year;_month = month;_day = day;}//拷贝构造Data(Data& d){cout << "Data(Data&)" << endl;_year = d._year;_month = d._month;_day = d._day;}
private:int _year;int _month;int _day;};
int main()
{Data d1(2006, 7, 20);Data d2(d1);Data d3 = d1;return 0;
}

        拷贝构造函数的第一个参数必须是类类型对象的引用,如果使用传值调用:

就会像下面这样,名称传参都会调用拷贝构造,调用完传参再次调用拷贝构造,无穷递归下去。

1.3.3、编译器默认生成的拷贝构造函数

        编译器默认生成的拷贝构造,对内置类型成员会完成值拷贝/浅拷贝(一个字节一个字节的拷贝),对自定义类型成员变量就会调用它的拷贝构造函数。

二、赋值运算符重载

        2.1、运算符重载

1、当运算符被用于类类型的对象时,C++语言允许我们通过运算符重载的形式指定新的含义。C++规定类类型对象使用运算符时,必须转换成调用对应运算符重载,若没有对应的运算符重载,则会编译报错。

2、运算符重载是具有特殊名字的函数,他的名字是由operator后面要定义的运算符共同构成。和其他函数一样,它也具有其返回类型和参数列表以及函数体。

3、重载运算符函数的参数个数和该运算符作用的运算对象数量一样多。一元运算符有一个参数,二元运算符有两个参数,二元运算符的左侧运算对象传给第一个参数,右侧运算对象传给第二个参数。

4、如果一个重载运算符函数是成员函数,则它的第一个运算对象默认传给隐式的this指针,因此运算符重载作为成员函数时,参数比运算对象少一个。

5、运算符重载以后,其优先级和结合性与对应的内置类型运算符保持一致。

6、不能通过连接语法中没有的符号来创建新的操作符:比如operator@

7、.*    ::   sizeof   ?:   .   注意以上5个运算符不能重载。(选择题里面常考,要记一
重载操作符至少有一个类类型参数,不能通过运算符重载改变内置类型对象的含义,如: int
operator+(int x,int y)

8、一个类需要重载哪些运算符,是看哪些运算符重载后有意义,比如Date类重载operator-就有意义,但是重载operator+就没有意义。

9、  重载++运算符时,有前置++和后置++,运算符重载函数名都是operator++,无法很好的区分。
        C++规定,后置++重载时,增加一个int形参,跟前置++构成函数重载,方便区分。

10、重载<<>>时,需要重载为全局函数,因为重载为成员函数,this指针默认抢占了第一个形参位置,第一个形参位置是左侧运算对象,调用时就变成了对象<<cout,不符合使用习惯和可读性。重载为全局函数把ostream/istream放到第一个形参位置就可以了,第二个形参位置当类类型对象。

有了运算符重载,对于自定义类型的对象,我们就可以像内置类型那样,直接进行+/-/+=/-= 等操作。(要 根据自定义类的需求写)。

应用举例:

        这里以日期类为例,实现一个运算符重载 ==

//运算符重载
// == 
bool Data::operator==(Data& d)
{if (_year == d._year && _month == d._month && _day == d._day){return true;}return false;
}

常见的运算符重载

        我们基本上可以重载所以的算术运算符、关系运算符和赋值运算符等,

算术运算符:+、-、*、/ ,用于自定义类型的算术运算。
关系运算符:==、!=、<、>、<=、>= ,用于自定义类型的比较操作。
赋值运算符:=,用于自定义类型的赋值操作。(当自定义类型(栈)包含动态分配的内存时,需要深拷贝以避免悬挂指针等问题。)
自增自减运算符:++、--,用于自定义类型的自增和自减操作。
下标运算符:[ ],用于自定义类型的数组或类似数组的操作。
流插入和提取运算符:<<、>>,用于自定义类型的输入输出操作。
函数调用运算符:(),允许自定义类型的对象像函数一样被调用。
成员访问运算符:->,一般 与智能指针或类似智能指针的类一起使用,用于访问指针所指向对象的成员。

前置++和后置++重载

C++规定

后置++重载时,增加一个int形参,跟前置++构成函数重载,方便区分。

前置++ 先使用再+1;而后置++是先+1再使用。

//前置++
Data& operator++();
//后置++
Data& operator++(int);

        2.2、赋值运算符重载

        赋值运算符重载是一个默认成员函数,用于完成两个已经存在的对象直接的拷贝赋值,这里要注意跟拷贝构造区分,拷贝构造用于一个对象拷贝初始化给另一个要创建的对象。

1、赋值运算符重载是一个运算符重载,规定必须重载为成员函数。赋值运算重载的参数建议写成1.const 当前类类型引用,否则会传值传参会有拷贝

2、有返回值,且建议写成当前类类型引用,引用返回可以提高效率,有返回值目的是为了支持连续赋值场景。

3、没有显式实现时,编译器会自动生成一个默认赋值运算符重载,默认赋值运算符重载行为跟默认拷3贝构造函数类似,对内置类型成员变量会完成值拷贝/浅拷贝(一个字节一个字节的拷贝),对自定义类型成员变量会调用他的赋值重载函数。

4、  像Date这样的类成员变量全是内置类型且没有指向什么资源,编译器自动生成的赋值运算符重载就4可以完成需要的拷贝,所以不需要我们显示实现赋值运算符重载。

        像Stack这样的类,虽然也都是内置类型,但是 a指向了资源,编译器自动生成的赋值运算符重载完成的值拷贝/浅拷贝不符合我们的需求,所以需要我们自己实现深拷贝(对指向的资源也进行拷贝)。

        像MyQueue这样的类型内部主要是自定义类型Stack成员,编译器自动生成的赋值运算符重载会调用Stack的赋值运算符重载也不需要我们显示实现MyQueue的赋值运算符重载。

这里还有一个小技巧,如果一个类显示实现了析构并释放资源,那么他就需要显示写赋值运算符重载,否则就不需要。

        现在就来哦实现日期类巩固这方面的知识。

        2.3、日期类的实现

Data.h:

#pragma once
#include<iostream>
#include<assert.h>
class Data
{friend std::ostream& operator<<(std::ostream& out, const Data& d);friend std::istream& operator>>(std::istream& in, Data& d);
public://构造函数Data(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}//析构//拷贝构造Data(Data& d){_year = d._year;_month = d._month;_day = d._day;}//输出void Print();//运算符重载bool operator==(Data& d);bool operator!=(Data& d);bool operator<(Data& d);bool operator<=(Data& d);bool operator>(Data& d);bool operator>=(Data& d);Data& operator+=(int day);Data& operator+(int day);Data& operator-=(int day);Data& operator-(int day);int operator-(Data& d);Data& operator++();Data& operator++(int);Data& operator--();Data& operator--(int);//ostream& operator<<(ostream& out);
private:int _year;int _month;int _day;
};

Data.cpp:

#include"Data.h"
using namespace std;//获得当前月份天数
int GetMonthDay(int year, int month)
{assert(month > 0 && month < 13);static int arr[13] = { -1,31,28,31,30,31,30,31,31,30,31,30,31 };if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 40 == 0))){return 29;}return arr[month];
}
//输出
void Data::Print()
{cout << _year << "年" << _month << "月" << _day << "日" << endl;
}
//运算符重载
// == 
bool Data::operator==(Data& d)
{if (_year == d._year && _month == d._month && _day == d._day){return true;}return false;
}
// !=
bool Data::operator!=(Data& d)
{return !(*this == d);
}// < 
bool Data::operator<(Data& d)
{if (_year < d._year){return true;}else if (_year == d._year && _month < d._month){return true;}else if (_year == d._year && _month == d._month && _day < d._day){return true;}return false;
}
//  <=
bool Data::operator<=(Data& d)
{return (*this) == d || (*this) < d;
}
// >
bool Data::operator>(Data& d)
{if (_year > d._year){return true;}else if (_year == d._year && _month > d._month){return true;}else if (_year == d._year && _month == d._month && _day > d._day){return true;}return false;
}
// +=
bool Data::operator>=(Data& d)
{return (*this) == d || (*this) > d;
}
Data& Data::operator+=(int day)
{_day += day;while (_day > GetMonthDay(_year, _month)){_day -= GetMonthDay(_year, _month);_month++;if (_month == 13){_month = 1;_year++;}}return *this;}
// +
Data& Data::operator+(int day)
{Data tmp = *this;tmp += day;return tmp;
}// -=
Data& Data::operator-=(int day)
{_day -=day;while (_day <= 0){_month--;if (_month == 0){_month = 12;_year--;}_day += GetMonthDay(_year, _month);}return (*this);
}
// - 天数
Data& Data::operator-(int day)
{Data d(*this);d -= day;return d;
}// - 日期
int Data::operator-(Data& d)
{Data min(*this);Data max(d);if ((*this) > d){min = d;max = *this;}int count = 0;while (min != max){count++;min += 1;}return count;}
//++
//前置++
Data& Data::operator++()
{(*this) += 1;return *this;
}
//后置++
Data& Data::operator++(int)
{Data d(*this);(*this) += 1;return d;
}//前置--
Data& Data::operator--()
{(*this) -= 1;return *this;
}
//后置--
Data& Data::operator--(int)
{Data d(*this);(*this) -= 1;return d;
}// <<
//ostream& Data::operator<<(ostream& out)
//{
//	out << _year << "年 " << _month << "月 " << _day << "日 " << endl;
//	return out;
//}
std::ostream& operator<<(std::ostream& out, const Data& d)
{cout << d._year << "年" << d._month << "月" << d._day << "日" << endl;return out;
}
//  >>
std::istream& operator>>(std::istream& in, Data& d)
{cout << "依次输入 年 月 日" << endl;in >> d._year >> d._month >> d._day;return in;
}

三、取地址运算符重载

        3.1、const 成员函数

1、 将const修饰的成员称之为从const成员函数,const成员放到成员函数参数列表的后面。

2、 const实际修饰该成员函数的this指针,表明在该成员函数中不能对类的任何成员进行修改。

3、 const修饰Data类的Print成员函数,

Print隐含的this指针由Data* const this 变为const Data* const this

#include<iostream>
using namespace std;
class Date
{
public:Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}// void Print(const Date* const this) constvoid Print() const{cout << _year << "-" << _month << "-" << _day << endl;}
private:int _year;int _month;int _day;
};
int main()
{// 这⾥⾮const对象也可以调⽤const成员函数是⼀种权限的缩⼩Date d1(2024, 7, 5);d1.Print();const Date d2(2024, 8, 5);d2.Print();return 0;
}

        3.2、 取地址运算符重载

        取地址运算符重载分为普通取地址运算符重载和const取地址运算符重载,一般这两个函数编译器自动生成的就可以够我们用了,不需要去显示实现。

class Data
{
public:Data* operator&(){return this;}const Data* operator&()const{return this;}
private:int _year;int _month;int _day;
};

这里我们不想要访问到类对象的地址,也可以返回nullptr。


http://www.ppmy.cn/news/1508650.html

相关文章

【Kubernetes】k8s集群Pod控制器

目录 一.Pod控制器作用 二.Pod控制器类型 1.Deployment&#xff08;简称deploy&#xff09; ReplicaSet&#xff08;简称rs&#xff09; 2.StatefulSet&#xff08;简称sts&#xff09; 创建SatefulSet控制器 3.DaemonSet&#xff08;简称ds&#xff09; 4.Job 5.Cron…

【项目】火灾烟雾检测管理系统。PyQT5+QT Designe+YOLOv8_ssod半监督算法+OpenCV

【项目】火灾烟雾检测管理系统。PyQT5QT DesigneYOLOv8_ssod半监督算法OpenCV 0.摘要1.引言2.烟雾检测算法2.0图像标注2.1 YOLOv8全监督算法结构2.2 Efficient-Teacher半监督算法结构 3.性能对比图4.源码、论文获取 0.摘要 火灾是常见而危险的自然灾害&#xff0c;不仅对人类生…

【Python】Python中一些有趣的用法

Python是一种非常灵活和强大的编程语言&#xff0c;它有很多有趣的用法&#xff0c;以下是一些例子&#xff1a; 一行代码实现FizzBuzz&#xff1a; print(\n.join([FizzBuzz[i%3*4:i%5*8:-1] or str(i) for i in range(1, 101)]))使用列表推导式生成斐波那契数列&#xff1a; …

在 CentOS 7 上安装 Redmine 的详细步骤及 20 个经典用法

目录 1. 引言 2. 安装步骤 2.1 更新系统 2.2 安装依赖包 2.3 安装 MariaDB 数据库 2.4 配置 MariaDB 2.5 安装 Ruby 2.6 安装 Redmine 2.7 配置 Redmine 2.8 安装 Bundler 和必要的 Gems 2.9 生成密钥并迁移数据库 2.10 配置 Apache 2.11 启动 Apache 并设置开机自…

ZLMediaKit如何结合webrtc实现双向对讲

目录 1. 安装和配置ZLMediaKit 2. 启用WebRTC模块 3. 创建WebRTC会话 4. 处理媒体流 5. 实现双向通信 6. 调试和测试 7. 安全性考虑 ZLMediaKit结合WebRTC实现双向对讲的过程涉及多个步骤&#xff0c;包括安装配置ZLMediaKit、启用WebRTC模块、创建WebRTC会话、处理媒体…

【LeetCode】将有序数组转换为二叉搜索树

目录 一、题目二、解法完整代码 一、题目 给你一个整数数组 nums &#xff0c;其中元素已经按 升序 排列&#xff0c;请你将其转换为一棵 平衡 二叉搜索树。 示例 1&#xff1a; 输入&#xff1a;nums [-10,-3,0,5,9] 输出&#xff1a;[0,-3,9,-10,null,5] 解释&#xff1…

知识改变命运 数据结构【杨辉三角(顺序表)】

杨辉三角 首先我们可以发现题目中返回类型是一个 这其实返回的类似与一个二维数组 我们大概分析下题目根据画图可知&#xff0c;我们可以把每一行的元素进行存储&#xff0c;然后再把每一行存储起来&#xff0c;然后就实现了题目 代码&#xff1a; public List<List<…

Unity初识

1&#xff1a;下载Unity Hub 下载地址&#xff1a;Unity官方下载_Unity最新版_从Unity Hub下载安装 | Unity中国官网 建议直接使用unity hub因为支持比较全面&#xff0c;适合新手 有中文 管理 编辑器等等功能支持 下载安装不过多介绍 2&#xff1a;Unity Hub汉化 因为我…

mysql主从服务配置

主从MySQL服务器 [rootlocalhost ~]# yum -y install ntpdate [rootlocalhost ~]# ntpdate cn.ntp.org.cn [rootlocalhost ~]# yum -y install rsync [rootlocalhost ~]# vim mysql.sh #!/bin/bash yum list installed |grep libaio if [ $? ne 0 ]; then yum -y install…

Forcepoint 网络安全解决方案

Forcepoint 作为全球领先的网络安全解决方案提供商&#xff0c;自 1994 年成立以来&#xff0c;便一直致力于为企业和政府机构提供最前沿、最有效的安全技术&#xff0c;以全力守护其最为珍贵的资产和数据。公司总部坐落于美国得克萨斯州奥斯汀市&#xff0c;凭借其卓越的技术实…

Java 多线程练习 (2024.8.12)

MultiProcessingExercise1 package MultiProcessingExercise20240812;public class MultiProcessingExercise1 {public static void main(String[] args) {// 设置、获取线程名称// 如果使用继承Thread类的方式实现多线程&#xff0c;那么可以直接通过set和get方法进行设置和获…

Oracle ACE是什么缩写?

大家都知道&#xff0c;Oracle有个ACE 计划&#xff0c;旨在奖励和表彰个人对 Oracle 社区做出的贡献。 这些贡献主要包括两方面&#xff1a; 知识与经验分享&#xff0c;如撰写博客、书籍和文章&#xff1b;制作视频教程&#xff1b;为开源项目做贡献&#xff1b;编写代码&a…

10分钟学会Docker的安装和使用

Docker 是一个用于开发、发布和运行应用程序的开源平台。它通过提供轻量级的容器技术&#xff0c;使得应用程序可以在任何环境中一致地运行。以下是快速学会Docker的安装和使用的步骤。 1. 安装Docker 在Windows上安装 下载Docker Desktop&#xff1a; 访问Docker官网下载适用…

Java->双击Window批处理程序动态切换Java版本

JDK8 echo off chcp 65001 >nul :: 设置控制台编码为UTF-8&#xff0c;避免中文乱码:: 检查是否以管理员身份运行 openfiles >nul 2>&1 if %errorlevel% neq 0 (echo 请求管理员权限...powershell -Command "Start-Process cmd -ArgumentList /c %~fnx0 -Ve…

13.1 Python 正则表达式基础

欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;欢迎订阅相关专栏&#xff1a; 工&#x1f497;重&#x1f497;hao&#x1f497;&#xff1a;野老杂谈 ⭐️ 全网最全IT互联网公司面试宝典&#xff1a;收集整理全网各大IT互联网公司技术、项目、HR面试真题.…

苹果发布 AirPods Pro 2 测试版固件 搭配iOS 18新特性

苹果今天发布了AirPods Pro 2 的第三个测试版固件&#xff0c;包括 Lightning 和 USB-C 两个版本。更新后的固件版本号为 7A5266c&#xff0c;高于 7A5244b&#xff0c;目前可供开发者使用。这是苹果公司自 6 月份宣布 AirPods Pro 2 新功能以来发布的第三个固件更新。 作为iOS…

git拉取后,代码不见了,没有冲突覆盖,且,没有删除,看我是怎么找回的

git拉取后&#xff0c;代码不见了&#xff0c;没有冲突覆盖&#xff0c;且&#xff0c;没有删除 重点提醒 当你的代码丢失时&#xff0c;不要惊慌&#xff0c;首先尝试使用本地的历史记录和远程仓库来找回代码。如果这些方法不起作用&#xff0c;你可以考虑其他的救援工具或寻…

搭建高可用OpenStack(Queen版)集群(十)之部署分布式存储Ceph

一、Ceph知识点学习 Ceph知识点学习&#xff1a;https://www.cnblogs.com/happy-king/p/9207509.html 二、部署分布式存储Ceph 一&#xff09;设置yum源 在全部控制与计算节点设置epel与ceph yum源 epel源&#xff1a;repo安装包下载_开源镜像站-阿里云 ceph源&#xff1a;cep…

在亚马逊云科技上利用生成式AI开发用户广告营销平台

项目简介&#xff1a; 小李哥将继续每天介绍一个基于亚马逊云科技AWS云计算平台的全球前沿AI技术解决方案&#xff0c;帮助大家快速了解国际上最热门的云计算平台亚马逊云科技AWS AI最佳实践&#xff0c;并应用到自己的日常工作里。 本次介绍的是如何利用亚马逊云科技大模型托…

windows 版本Jenkins的Jenkinsfile中共享变量

场景 jenkins部署在windows服务器上的&#xff0c;需要在Jenkinsfile中获取命令执行的结果存入一个变量&#xff0c;然后在后续的执行中使用此变量 一开始想的是定义一个环境变量&#xff0c;如下所示&#xff0c; pipeline {agent anystages {stage(test) {steps {bat for /…