C++之类与对象(中)(上篇)

news2024/12/27 2:45:19

类与对象(中)

类的默认成员函数

默认成员函数就是⽤⼾没有显式实现,编译器会⾃动⽣成的成员函数称为默认成员函数。⼀个类,我 们不写的情况下编译器会默认⽣成以下6个默认成员函数,需要注意的是这6个中最重要的是前4个,最 后两个取地址重载不重要,我们稍微了解⼀下即可。其次就是C++11以后还会增加两个默认成员函数, 移动构造和移动赋值,这个我们后⾯再讲解。默认成员函数很重要,也⽐较复杂,我们要从两个⽅⾯ 去学习:

• 第⼀:我们不写时,编译器默认⽣成的函数⾏为是什么,是否满⾜我们的需求。

• 第⼆:编译器默认⽣成的函数不满⾜我们的需求,我们需要⾃⼰实现,那么如何⾃⼰实现?

在这里插入图片描述

构造函数

构造函数是特殊的成员函数,需要注意的是,构造函数虽然名称叫构造,但是构造函数的主要任务并 不是开空间创建对象(我们常使⽤的局部对象是栈帧创建时,空间就开好了),⽽是对象实例化时初始化 对象。构造函数的本质是要替代我们以前Stack和Date类中写的Init函数的功能,构造函数⾃动调⽤的 特点就完美的替代的了Init。

构造函数的特点:

函数名与类名相同。

⽆返回值。 (返回值啥都不需要给,也不需要写void,不要纠结,C++规定如此)

对象实例化时系统会⾃动调⽤对应的构造函数。(最重要的一点

构造函数可以重载。

(上面几个为一组,下面几个是上面的深入理解)

如果类中没有显式定义构造函数,则C++编译器会⾃动⽣成⼀个⽆参的默认构造函数,⼀旦⽤⼾显 式定义编译器将不再⽣成。

⽆参构造函数、全缺省构造函数、我们不写构造时编译器默认⽣成的构造函数,都叫做默认构造函 数。但是这三个函数有且只有⼀个存在,不能同时存在。⽆参构造函数和全缺省构造函数虽然构成 函数重载,但是调⽤时会存在歧义。要注意很多同学会认为默认构造函数是编译器默认⽣成那个叫 默认构造,实际上⽆参构造函数、全缺省构造函数也是默认构造,总结⼀下就是不传实参就可以调 ⽤的构造就叫默认构造

我们不写,编译器默认⽣成的构造,对内置类型成员变量的初始化没有要求,也就是说是是否初始 化是不确定的,看编译器。对于⾃定义类型成员变量,要求调⽤这个成员变量的默认构造函数初始 化。如果这个成员变量,没有默认构造函数,那么就会报错,我们要初始化这个成员变量,需要⽤ 初始化列表才能解决,初始化列表。

说明:C++把类型分成内置类型(基本类型)和⾃定义类型。内置类型就是语⾔提供的原⽣数据类型,如:int/char/double/指针等,⾃定义类型就是我们使⽤class/struct等关键字⾃⼰定义的类型。

#include<iostream>
using namespace std;
class Date
{
public:
// 1.⽆参构造函数
Date()
{
_year = 1;
_month = 1;
_day = 1;
}
// 2.带参构造函数
Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
// 3.全缺省构造函数
/*Date(int year = 1, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}*/
void Print()
{
cout << _year << "/" << _month << "/" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
// 如果留下三个构造中的第⼆个带参构造,第⼀个和第三个注释掉
// 编译报错:error C2512: “Date”: 没有合适的默认构造函数可⽤
Date d1; // 调⽤默认构造函数
Date d2(2025, 1, 1); // 调⽤带参的构造函数
// 注意:如果通过⽆参构造函数创建对象时,对象后⾯不⽤跟括号,否则编译器⽆法
// 区分这⾥是函数声明还是实例化对象
// warning C4930: “Date d3(void)”: 未调⽤原型函数(是否是有意⽤变量定义的?)
Date d3();
d1.Print();
d2.Print();
return 0;
}

结论:一般构造函数需要自己写,少数情况下,默认生成就可以用

析构函数

析构函数与构造函数功能相反,析构函数不是完成对对象本⾝的销毁,⽐如局部对象是存在栈帧的, 函数结束栈帧销毁,他就释放了,不需要我们管,C++规定对象在销毁时会⾃动调⽤析构函数,完成对 象中资源的清理释放⼯作。析构函数的功能类⽐我们之前Stack实现的Destroy功能,⽽像Date没有 Destroy,其实就是没有资源需要释放,所以严格说Date是不需要析构函数的。

析构函数的特点:

  1. 析构函数名是在类名前加上字符 ~。

  2. ⽆参数⽆返回值。 (这⾥跟构造类似,也不需要加void)

  3. ⼀个类只能有⼀个析构函数。若未显式定义,系统会⾃动⽣成默认的析构函数。

  4. 对象⽣命周期结束时,系统会⾃动调⽤析构函数。

  5. 跟构造函数类似,我们不写编译器⾃动⽣成的析构函数对内置类型成员不做处理,⾃定类型成员会 调⽤他的析构函数。

  6. 还需要注意的是我们显⽰写析构函数,对于⾃定义类型成员也会调⽤他的析构,也就是说⾃定义类 型成员⽆论什么情况都会⾃动调⽤析构函数。

  7. 如果类中没有申请资源时,析构函数可以不写,直接使⽤编译器⽣成的默认析构函数,如Date;如 果默认⽣成的析构就可以⽤,也就不需要显⽰写析构,如MyQueue;但是有资源申请时,⼀定要 ⾃⼰写析构,否则会造成资源泄漏,如Stack。

  8. ⼀个局部域的多个对象,C++规定后定义的先析构。

注意点:前四点是基本的认识,后面四点是具体补充

总结:一般情况下,显示申请资源了,才需要自己实现析构,其他情况下基本不需要显示写

这里面我们还需要分清楚栈帧的创建和销毁和动态内存开辟空间的区别

在这里插入图片描述

动态内存开辟需要我们手动去销毁,否则会造成内存的泄漏

#include<iostream>
using namespace std;
typedef int STDataType;
class Stack
{
public:
Stack(int n = 4)
{
_a = (STDataType*)malloc(sizeof(STDataType) * n);
if (nullptr == _a)
{
perror("malloc申请空间失败");
return;
}
_capacity = n;
_top = 0;
}
~Stack()
{
cout << "~Stack()" << endl;
free(_a);
_a = nullptr;
_top = _capacity = 0;
}
private:
STDataType* _a;
size_t _capacity;
size_t _top;
};
// 两个Stack实现队列
class MyQueue
{
public:
//编译器默认⽣成MyQueue的析构函数调⽤了Stack的析构,释放的Stack内部的资源
// 显⽰写析构,也会⾃动调⽤Stack的析构
/*~MyQueue()
{}*/
private:
Stack pushst;
Stack popst;
};
int main()
{
Stack st;
MyQueue mq;
return 0;
}

回忆之前做过的题:
有效的括号

题目如下:

给定一个只包括 '('')''{''}''['']' 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合。
  2. 左括号必须以正确的顺序闭合。
  3. 每个右括号都有一个对应的相同类型的左括号。

示例 1:

输入:s = "()"
输出:true

示例 2:

输入:s = "()[]{}"
输出:true

示例 3:

输入:s = "(]"
输出:false

提示:

  • 1 <= s.length <= 104
  • s 仅由括号 '()[]{}' 组成

对⽐⼀下⽤C++和C实现的Stack解决之前括号匹配问题isValid,我们发现有了构造函数和析构函数确 实⽅便了很多,不会再忘记调⽤Init和Destory函数了,也⽅便了不少。

这是C语言版本的题解:

typedef char STDataType;
typedef struct Stack
{
    STDataType* arr;
    int capacity;
    int top;
}ST;
void STInit (ST*ps)
{
    assert(ps);
    ps->arr=NULL;
    ps->capacity=ps->top=0;
}
void STDestroy(ST*ps)
{
    assert(ps);
    if(ps->arr)
        free(ps->arr);
        ps->arr=NULL;
        ps->capacity=ps->top=0;
}
void STPush(ST*ps,STDataType x)
{
    assert(ps);
    if(ps->capacity==ps->top)
    {
        int newCapacity=ps->capacity==0?4:2*ps->capacity;
        STDataType*tmp=(STDataType*)realloc(ps->arr,newCapacity*sizeof(STDataType));
        if(tmp==NULL)
        {
            perror("realloc fail!");
            exit(1);
        }
        ps->arr=tmp;
        ps->capacity=newCapacity;

    }
    ps->arr[ps->top++]=x;
}
bool StackEmpty(ST*ps)
{
    assert(ps);
    return ps->top==0;
}
void STPop(ST*ps)
{
    assert(ps);
    assert(!StackEmpty(ps));
    --ps->top;
}
int STSize(ST*ps)
{
    assert(ps);
    return ps->top;
}
STDataType StackTop(ST*ps) {
    return ps->arr[ps->top-1];
}

bool isValid(char* s) {
    ST st;
    STInit(&st);
    //遍历字符串s
    char*ps=s;
    while(*ps!='\0')
    {
        //左括号,入栈
        if(*ps=='('||*ps=='['||*ps=='{')
        {
            STPush(&st,*ps);
        }
        else//右括号,和栈顶元素比较是否匹配
        {
            if(StackEmpty(&st))
            {
                return false;
            }
            char ch=StackTop(&st);
            if((*ps==')'&&ch=='(')
            ||(*ps==']'&&ch=='[')
            ||(*ps=='}'&&ch=='{'))
            {
                STPop(&st);
            }else{
                STDestroy(&st);
                //不匹配
                return false;
            }
        }
        ps++;
    }
    bool ret=StackEmpty(&st)==true;
    //销毁
    STDestroy(&st);
    return ret;
    
}

这是C++的题解

#include<iostream>
using namespace std;
// ⽤最新加了构造和析构的C++版本Stack实现
bool isValid(const char* s) {
Stack st;
while (*s)
{
if (*s == '[' || *s == '(' || *s == '{')
{
st.Push(*s);
}
else
{
// 右括号⽐左括号多,数量匹配问题
if (st.Empty())
{
return false;
}
// 栈⾥⾯取左括号
char top = st.Top();
st.Pop();
// 顺序不匹配
if ((*s == ']' && top != '[')
|| (*s == '}' && top != '{')
|| (*s == ')' && top != '('))
{
return false;
}
}
++s;
}
// 栈为空,返回真,说明数量都匹配 左括号多,右括号少匹配问题
return st.Empty();
}
// ⽤之前C版本Stack实现
bool isValid(const char* s) {
ST st;
STInit(&st);
while (*s)
{
// 左括号⼊栈
if (*s == '(' || *s == '[' || *s == '{')
{
STPush(&st, *s);
}
else // 右括号取栈顶左括号尝试匹配
{
if (STEmpty(&st))
{
STDestroy(&st);
return false;
}
char top = STTop(&st);
STPop(&st);
// 不匹配
if ((top == '(' && *s != ')')
|| (top == '{' && *s != '}')
|| (top == '[' && *s != ']'))
{
STDestroy(&st);
return false;
}
}
++s;
}
// 栈不为空,说明左括号⽐右括号多,数量不匹配
bool ret = STEmpty(&st);
STDestroy(&st);
return ret;
}
int main()
{
cout << isValid("[()][]") << endl;
cout << isValid("[(])[]") << endl;
return 0;
}

拷⻉构造函数

如果⼀个构造函数的第⼀个参数是⾃⾝类类型的引⽤,且任何额外的参数都有默认值,则此构造函数 也叫做拷⻉构造函数,也就是说拷⻉构造是⼀个特殊的构造函数。

拷⻉构造的特点:

  1. 拷⻉构造函数是构造函数的⼀个重载。

  2. 拷⻉构造函数的第⼀个参数必须是类类型对象的引⽤,使⽤传值⽅式编译器直接报错,因为语法逻 辑上会引发⽆穷递归调⽤。 拷⻉构造函数也可以多个参数,但是第⼀个参数必须是类类型对象的引 ⽤,后⾯的参数必须有缺省值。

  3. C++规定⾃定义类型对象进⾏拷⻉⾏为必须调⽤拷⻉构造,所以这⾥⾃定义类型传值传参和传值返 回都会调⽤拷⻉构造完成。

  4. 若未显式定义拷⻉构造,编译器会⽣成⾃动⽣成拷⻉构造函数。⾃动⽣成的拷⻉构造对内置类型成 员变量会完成值拷⻉/浅拷⻉(⼀个字节⼀个字节的拷⻉),对⾃定义类型成员变量会调⽤他的拷⻉构 造。

  5. 像Date这样的类成员变量全是内置类型且没有指向什么资源,编译器⾃动⽣成的拷⻉构造就可以完 成需要的拷⻉,所以不需要我们显⽰实现拷⻉构造。像Stack这样的类,虽然也都是内置类型,但 是_a指向了资源,编译器⾃动⽣成的拷⻉构造完成的值拷⻉/浅拷⻉不符合我们的需求,所以需要 我们⾃⼰实现深拷⻉(对指向的资源也进⾏拷⻉)。像MyQueue这样的类型内部主要是⾃定义类型 Stack成员,编译器⾃动⽣成的拷⻉构造会调⽤Stack的拷⻉构造,也不需要我们显⽰实现 MyQueue的拷⻉构造。这⾥还有⼀个⼩技巧,如果⼀个类显⽰实现了析构并释放资源,那么他就 需要显⽰写拷⻉构造,否则就不需要。

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

C++规定:类类型传值传参必须调用拷贝构造

在这里插入图片描述

看上面这张图,首先传参调用的时候,参数会去拷贝构造,拷贝构造完成之后再回到函数内部,最后到主函数

为什么这里要用到引用呢?

每次调用拷贝构造函数之前要先传值传参,传值传参是一种拷贝,又形成一个新的拷贝构造,就形成了无穷递归

#include<iostream>
using namespace std;
class Date
{
public:
Date(int year = 1, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
// 编译报错:error C2652: “Date”: ⾮法的复制构造函数: 第⼀个参数不应是“Date”
//Date(Date d)
Date(const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
// 不是拷贝构造,就是一个普通构造,对于指针来说,不需要进行拷贝构造,只需要传地址即可
Date(Date* d)
{
_year = d->_year;
_month = d->_month;
_day = d->_day;
}
void Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
void Func1(Date d)
{
cout << &d << endl;
d.Print();
}
// Date Func2()
Date& Func2()
{
Date tmp(2024, 7, 5);
tmp.Print();
return tmp;
}
int main()
{
Date d1(2024, 7, 5);
// C++规定⾃定义类型对象进⾏拷⻉⾏为必须调⽤拷⻉构造,所以这⾥传值传参要调⽤拷⻉
构造
// 所以这⾥的d1传值传参给d要调⽤拷⻉构造完成拷⻉,传引⽤传参可以较少这⾥的拷⻉
Func1(d1);
cout << &d1 << endl;
// 这⾥可以完成拷⻉,但是不是拷⻉构造,只是⼀个普通的构造
Date d2(&d1);
d1.Print();
d2.Print();
//这样写才是拷⻉构造,通过同类型的对象初始化构造,⽽不是指针
Date d3(d1);
d2.Print();
// 也可以这样写,这⾥也是拷⻉构造
Date d4 = d1;
d2.Print();
// Func2返回了⼀个局部对象tmp的引⽤作为返回值
// Func2函数结束,tmp对象就销毁了,相当于了⼀个野引⽤
Date ret = Func2();
ret.Print();
return 0;
}

来看下面的场景:
在这里插入图片描述

这里需要添加const ,才能保证不会报错,因为这里面,在栈区的变量出了作用域会被销毁,然后会有一个临时变量拷贝,,作为实参传递给形参,权限放大了,会出现问题,const修饰的话,可以引用普通的也可以引用const修饰的

权限放大是因为临时对象变量具有常性,不能修改,但是Date引用可以修改,所以就造成了权限放大

接下来看一下用栈实现队列的题目如何完成:

题目如下:

请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(pushpoppeekempty):

实现 MyQueue 类:

  • void push(int x) 将元素 x 推到队列的末尾
  • int pop() 从队列的开头移除并返回元素
  • int peek() 返回队列开头的元素
  • boolean empty() 如果队列为空,返回 true ;否则,返回 false

说明:

  • 只能 使用标准的栈操作 —— 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。
  • 你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。

示例 1:

输入:
["MyQueue", "push", "push", "peek", "pop", "empty"]
[[], [1], [2], [], [], []]
输出:
[null, null, null, 1, 1, false]

解释:
MyQueue myQueue = new MyQueue();
myQueue.push(1); // queue is: [1]
myQueue.push(2); // queue is: [1, 2] (leftmost is front of the queue)
myQueue.peek(); // return 1
myQueue.pop(); // return 1, queue is [2]
myQueue.empty(); // return false

提示:

  • 1 <= x <= 9
  • 最多调用 100pushpoppeekempty
  • 假设所有操作都是有效的 (例如,一个空的队列不会调用 pop 或者 peek 操作)
#include<iostream>
using namespace std;
typedef int STDataType;
class Stack
{
public:
Stack(int n = 4)
{
_a = (STDataType*)malloc(sizeof(STDataType) * n);
if (nullptr == _a)
{
perror("malloc申请空间失败");
return;
}
_capacity = n;
_top = 0;
}
Stack(const Stack& st)
{
// 需要对_a指向资源创建同样⼤的资源再拷⻉值
    _a = (STDataType*)malloc(sizeof(STDataType) * st._capacity);
if (nullptr == _a)
{
perror("malloc申请空间失败!!!");
return;
}
memcpy(_a, st._a, sizeof(STDataType) * st._top);
_top = st._top;
_capacity = st._capacity;
}
void Push(STDataType x)
{
if (_top == _capacity)
{
int newcapacity = _capacity * 2;
STDataType* tmp = (STDataType*)realloc(_a, newcapacity *
sizeof(STDataType));
if (tmp == NULL)
{
perror("realloc fail");
return;
}
_a = tmp;
_capacity = newcapacity;
}
_a[_top++] = x;
}
~Stack()
{
cout << "~Stack()" << endl;
free(_a);
_a = nullptr;
_top = _capacity = 0;
}
private:
STDataType* _a;
size_t _capacity;
size_t _top;
};
// 两个Stack实现队列
class MyQueue
{
public:
private:
Stack pushst;
Stack popst;
};
int main()
{
Stack st1;
st1.Push(1);
st1.Push(2);
// Stack不显⽰实现拷⻉构造,⽤⾃动⽣成的拷⻉构造完成浅拷⻉
// 会导致st1和st2⾥⾯的_a指针指向同⼀块资源,析构时会析构两次,程序崩溃
Stack st2 = st1;
MyQueue mq1;
// MyQueue⾃动⽣成的拷⻉构造,会⾃动调⽤Stack拷⻉构造完成pushst/popst
// 的拷⻉,只要Stack拷⻉构造⾃⼰实现了深拷⻉,他就没问题
MyQueue mq2 = mq1;
return 0;
}

在这里插入图片描述

这里再来强调一下对于局部变量的引用,这是万万不可以的,因为局部变量储存在栈区,局部变量出了栈区,会被销毁,所以再去引用调用的时候会出现问题,也就是野引用的情况

如果不想出现问题,可以考虑在前面加上static,被static修饰的变量,不会储存在栈区,会储存在静态区

希望能对你有所帮助,没能帮上我会有点小伤心TT
在这里插入图片描述

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

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

相关文章

ECCV 2024 | 南洋理工三维数字人生成新范式:结构扩散模型

该论文作者均来自于新加坡南洋理工大学 S-Lab 团队&#xff0c;包括博士后胡涛&#xff0c;博士生洪方舟&#xff0c;以及计算与数据学院刘子纬教授&#xff08;《麻省理工科技评论》亚太地区 35 岁以下创新者&#xff09;。S-Lab 近年来在顶级会议如 CVPR, ICCV, ECCV, NeurIP…

ICE.AI战略扩展亚太市场,创新交易模式及平台全面升级

2024年8月11日,纽约——全球金融科技领军企业,Intercontinental Exchange Inc.宣布,公司将加速在亚太市场的战略扩展,并通过进一步优化交易模式和平台功能,巩固其在全球市场的卓越地位,同时积极探索新的获利机会。 ICE.AI自推行以来,凭借前沿的人工智能技术和深度学习算法,为全…

shell编程:利用SSH实现分布式应用的一键安装部署②(脚本安装java环境、脚本安装配置zookeeper、scala、kafka)

上一节&#xff1a;函数封装 ②脚本安装java环境、脚本安装配置zookeeper、scala、kafka 1 脚本一键部署kafka分布式应用 1.1 脚本安装配置java环境 准备好java安装包&#xff0c;存放到/opt/tmp目录下。我这里使用的是jdk-8u212-linux-x64.tar.gz&#xff0c;在网上找对应…

excel向下合并空值

方方格子&#xff1a;合并转换——合并空值 选择向右或者向下

基于ssm+vue+uniapp的英语学习交流平台小程序

开发语言&#xff1a;Java框架&#xff1a;ssmuniappJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;M…

【网络】套接字(socket)编程——UDP版

1.socket 1.1.什么是socket Socket 的中文翻译过来就是“套接字”。 套接字是什么&#xff0c;我们先来看看它的英文含义&#xff1a;插座。 Socket 就像一个电话插座&#xff0c;负责连通两端的电话&#xff0c;进行点对点通信&#xff0c;让电话可以进行通信&#xff0c;端…

鸿蒙(API 12 Beta3版)【音视频解封装】 文件解析封装

开发者可以调用本模块的Native API接口&#xff0c;完成音视频解封装&#xff0c;即从比特流数据中取出音频、视频等媒体帧数据。 当前支持的数据输入类型有&#xff1a;远程连接(http协议、HLS协议)和文件描述符(fd)。 支持的解封装格式如下&#xff1a; 媒体格式封装格式码…

高效修复,2024年SD卡损坏数据恢复利器推荐

如果你也是爱记录生活的小伙伴外出游玩的时候肯定会带上带你的长枪短炮吧。如果预算充足可以直接考虑双盘位的设备&#xff0c;为你的图片上个保险。如果是单卡槽的设备回来的时候发现照片全无了咋办&#xff0c;这次我们就探讨下sd卡数据恢复要怎么进行吧。 1.福昕恢复数据 …

【递归】3.反转链表

leetcode题目连接&#xff1a;https://leetcode.cn/problems/reverse-linked-list/题解过程&#xff1a; 1.找到重复的子问题 要逆序第一个节点&#xff0c;就把后面的节点都逆序一遍 2.关注到具体的子问题的实现 第一步&#xff1a;将当前节点的后面所有节点逆置 第二步&…

【自动驾驶】ROS中自定义格式的服务通信,含命令行动态传参(c++)

目录 通信流程创建服务器端及客户端新建服务通讯文件修改service的xml及cmakelistCMakeLists.txt编辑 msg 相关配置编译消息相关头文件在cmakelist中包含头文件的路径在service包下编写service.cpp在client包下编写client.cpp测试运行查询服务的相关指令列出目前的所有服务&…

毛骨悚然,ChatGPT诡异尖叫、模仿用户说话,GPT-4o被曝行为失控

ChatGPT被曝存在失控行为&#xff0c;原本是用户和ChatGPT正常的语音对话&#xff0c;但ChatGPT却突然大喊了一声“no”&#xff0c;随即竟模仿起了用户的声音&#xff01; 下面就是这段让人毛骨悚然的声音片段&#xff1a; ChatGPT失控行为首次公开很多网友表示&#xff0c;第…

【MySQL】2.MySQL实际操作

目录 一、数据分析基本流程 注&#xff1a;Navicat快捷键 二、获取数据后的代码操作 &#xff08;1&#xff09;探索数据&#xff0c;查看定义 &#xff08;2&#xff09;筛选有用的字段 &#xff08;3&#xff09;建新表&#xff08;查询建表插值 三合一&#xff09; 注意…

揭秘Java 8新宠儿:初识Optional,让你的代码告别空指针烦恼

文章目录 前言一、Optional基础二、使用步骤1.创建Optional实例1.常用方法 前言 Java 8 引入了一个非常有用的类 Optional&#xff0c;它旨在减少空指针异常&#xff08;NullPointerException&#xff09;的发生。Optional 类是一个可以包含也可以不包含非null值的容器对象。如…

20240813在荣品RK3588S-AHD开发板的预置Android13中挂载ext4格式的256GB的TF卡

df -h mount fdisk无效 20240813在荣品RK3588S-AHD开发板的预置Android13中挂载ext4格式的256GB的TF卡 2024/8/13 11:24 缘起&#xff1a;当时比较便宜96.9&#xffe5;/想看看256GB的TF卡的高速卡的效果&#xff0c;就在京东入手了3张三星的高速TF卡。最近在弄RK3588S&#xf…

4款AI自动生成PPT神器,制作PPT太容易了

在当今数字化时代&#xff0c;无论是职场人士还是在校学生&#xff0c;PPT已经成为工作和学习中不可或缺的展示工具。从项目回顾到学术答辩&#xff0c;甚至是婚礼致辞&#xff0c;一份精心制作的PPT总能给人留下深刻印象。 为了帮助您更高效地完成PPT制作&#xff0c;我们将介…

数据科学、数据分析、人工智能必备知识汇总-----常用数据分析方法-----持续更新

数据科学、数据分析、人工智能必备知识汇总-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/140174015 文章目录 一、对比分析法1. 按时间和地区2. 同比和环比 二、分组分析法三、结构分析法四、交叉分析法五、矩阵分…

【话题】AI时代的程序员:挑战、机遇与核心竞争力的重塑

目录 人工智能时代&#xff0c;程序员如何保持核心竞争力&#xff1f; ​编辑引言 方向一&#xff1a;AI辅助编程对程序员工作的影响 案例 潜在的风险与对策 方向二&#xff1a;程序员应重点发展的核心能力 核心竞争力 如何培养这些能力 方向三&#xff1a;人机协作模式下的职业…

图论------贝尔曼-福德(Bellman-Ford)算法

算法概述&#xff1a; Bellman-Ford算法核心代码如下 for(int i 1;i<n-1;i) for(int j 1;j<m;j) if(dic[v[j]]> dic[u[j]] w[j]] dic[v[j]] dic[u[j]] w[j]; 首先我们要了解一个点就是我们这次不再使用邻接矩阵来存储图的信息&#xff0c;而是定义三个一维数组来…

Kubernetes之pod的污点和容忍度

污点和容忍度 污点&#xff08;Taint&#xff09;&#xff0c;它使节点能够排斥一类特定的 Pod。 容忍度&#xff08;Toleration&#xff09; 是应用于 Pod 上的&#xff0c;容忍度允许调度器调度带有对应污点的 Pod。 容忍度允许调度但并不保证调度&#xff1a;作为其功能的…

构建即时通讯应用:Spring boot高效集成WebSocket、Stomp协议完成前后端持续通信

1. 引入依赖 在你的Spring Boot项目的pom.xml中添加以下依赖&#xff1a; <dependencies><!-- Spring Boot Starter Thymeleaf --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf&…