【C++深入学习】类和对象(一)

news/2024/9/13 22:47:06/ 标签: c++, 学习, 开发语言, 笔记

在这里插入图片描述

欢迎来到Harper·Lee的学习笔记
博主主页传送门:Harper·Lee博客主页!
欢迎各位大佬交流学习


在这里插入图片描述

本篇本章正式进入C++的类和对象部分,本部分知识分为三小节。
复习:

  1. 结构体复习–内存对齐
  2. 编译和链接
  3. 函数栈桢的创建和销毁

一、面向过程与面向对象

1.1 面向过程

在之前学习的C语言是一种面向过程的语言,它关注的是求解问题的具体实现过程,一般通过函数调用逐步解决问题。就比如说我们以面向过程的方式分析淘米:
QQ截图20240713110621.png

1.2 面向对象

C++就是一种面向对象的语言,它将一个问题分成多个对象,更强调对象与对象之间的联系。在淘米煮饭这个例子中,一共有四个对象:米、水、锅、人。
整个过程中,这四个对象之间是交互完成任务的。在面向对象中,我们更强调对象之间的连续,并不太在意其内在是如何完成的。
QQ截图20240713110653.png

二、类的定义(class/struct)

2.1 类定义格式

  1. class是定义类的关键字,Stack是类的名称,{ }中是类的主体,注意类定义结束时后面的分号不能省略。类中的内容叫做类的成员,包括:类的属性或成员变量;类中的函数称为类的方法或成员函数。C语言中的结构体是类和函数分离的,但是C++不是。
#include<iostream>
using namespace std;
class className//类的定义方式1——class
{//成员函数void Push(int x);void Pop();int Top();//成员变量int* a;//数组int top;int capacity;
};
  1. C++将C语言中的结构体升级为类。C语言中结构体只能定义变量,在C++中,类不仅可以定义变量,还可以定义函数。
    | struct 在C/C++中的用法不同点 | C语言 | C++ |
    | — | — | — |
    |
    1. 可以定义的内容
    | struct 只能定义变量 | struct可以定义变量、函数 |
    |
    2. 类型
    | struct +结构体名 | 类名 |
    |
    3. 定义变量的方法
    | struct +结构体名才可以定义变量 | 直接类名即可定义,不需要struct 关键字,也可以写(旧法) |
    |
    4. typedef
    | 通常用typedef使类型名称简单些 | 直接类名就可以用 |
    |
    5. 能否定义类
    | C语言中struct 可以定义类 | C++中struct 可以定义类 |
//test.c
//在C语言中,一般都会使用typedef
struct Node1//结构体
{struct Node1* next;//注意这里:struct Node1*才是类型名,才能用它定义变量nextint val;
};//test.cpp
#include<iostream>
using namespace std;
struct Node2//类的定义方式2——struct
{Node2* next;//区别改变在这里,直接用类名,int val;void top();
};//这一中在C语言中是不能通过的!!!!C++兼容C语言,C语言不兼容C++!!!
int main()
{//test.cppNode2 n1;//定义n1struct Node2 n2;//定义n2,C语言的用法C++也支持!return 0;
}
  1. 定义在类里面的函数默认为 inline 内联的。

也可以进行声明和定义的分离(比如声明和定义在不同文件中)
**a. 声明和定义没有分离。**注意:成员函数如果在类中定义,编译器可能会将其当成内联函数处理

//1. 声明和定义没有分离:
#include<iostream>
using namespace std;
class Date
{
public:void Init(int year, int month, int day){_year = year;month = month;day = day;}private:int _year;int _month;int _day;
};

b.声明和定义分离。声明放在头文件(.h)中,定义放在源文件(.cpp)中。 声明和定义分离需要指定类域,就使用了::域作用限定符。
QQ截图20240713110724.png

//test.h
#include<iostream>
using namespace std;
class Date
{
public:void Init(int year, int month, int day);//声明
private:int year;int month;int day;
};//test.cpp
void Date::Init(int year, int month, int day)//定义//声明和定义分离需要指定类域,就使用了域作用限定符
{			                                 //Init是类Date的成员函数,只是声明和定义分离了而已year = year;month = month;day = day;
}

2.2 类的访问限定符

在C++中有三种访问限定符:public、private、protected
QQ截图20240713110744.png

  1. public修饰的成语言在类外可以直接被访问;
  2. protected和private修饰的成员在类外不能直接被访问;
  3. 访问权限作用域从该访问限定符出现的位置开始一直到下一个访问限定符出现为止,如果后面没有访问限定符,作用域就到 } 即类结束;
  4. class的默认访问限定符是private,struct的默认访问限定符是public。(因为struct要兼容C)
  5. ⼀般成员变量都会被限制为private/protected,需要给别人使用的成员函数会放为public。protected一般在继承中比较常用。
#include<iostream>
using namespace std;
class Date
{
public://可以访问void Init(int year, int month, int day)//非成员变量{_year = year;_month = month;_day = day;}
private://不可以访问int _year;//成员变量int _month;int _day;
};

2.3 成员变量与非成员变量的区分

从下面的代码可以看出,类中的成员变量和非成员变量之间存在着重名冲突。

#include<iostream>
using namespace std;
class Date
{
public:void Init(int year, int month, int day)//非成员变量{year = year;month = month;day = day;}
private:int year;//成员变量int month;int day;
};

C++标准并没有规定成员变量的命名规则。为了区分出成员变量,惯例上,我们在定义成员变量时会对其进行特定地修饰,比如_变量名或者是m_变量名或者变量名_。 不同公司可能都有一套自己的命名规则,但目的只是为了区分出成员变量。

#include<iostream>
using namespace std;
class Date
{
public:void Init(int year, int month, int day)//非成员变量{_year = year;_month = month;_day = day;}
private:int _year;//成员变量int _month;int _day;
};

2.4 变量声明和定义的区别

  1. 变量的声明:告知变量的名称、类型,没有开辟空间;

  2. 变量的定义:开辟了空间。如果是定义,就有空间,就可以直接使用/访问。如下面main函数中的_year。

#include<iostream>
using namespace std;
class Date
{
public:void Init(int year, int month, int day);//声明
private:int _year;//是定义还是声明????————声明int _month;int _day;
};//test.cpp
void Date::Init(int year, int month, int day)//定义
{			                              _year = year;_month = month;_day = day;
}
int main()
{Date::_year = 2024;//error,所以不能直接使用变量,说明没有开辟空间,_year是声明return 0;
}

三、类的作用域

3.1 类域的基本特点

  1. 同一个域里面不能定义同名变量,但是不同的域里面可以定义重名变量。
  2. 类域和命名空间域只影响名字隔离,不影响各自的生命周期
  3. 类域影响的是编译的查找规则, 查找默认在局部和空间去找,不会在命名空间域中去查找,除非使用== ::限定符 ==指定了类域。

3.2 编译器的查找规则

  1. (图源于博主:vpurple__)

屏幕截图 2024-07-04 172820.png


屏幕截.png

四、类对象模型

4.1 类对象的实例化

类:是对对象进行描述的、就像模型一样的东西。
类限定了类有哪些成员,类中的成员变量是一种声明,并没有分配实际的内存空间来存储它。就比如我们可以根据一张图纸(没有实际空间),创建出好几座不一样的房屋(有实际空间)。二者不一样的房子就是类实例化出的对象。
QQ截图20240713110821.png
用类名定义对象的方式,称为类的实例化。单独的类并不占据实际空间。而且一个类可以实例化出多个对象,实例化出的对象占用实际的物理空间,存储类的成员变量。

#include<iostream>
using namespace std;class Date//类
{
public:void Init(int year, int month, int day){_year = year;_month = month;_day = day;}void Print(){cout << _year << "-" << _month << "-" << _day << endl;}
private://这里只是声明,没有开实际空间int _year;int _month;int _day;};
int main()
{//实例化出d1,d2两个对象Date d1;//Date类名就是一个类型,直接用来定义Date d2;d1.Init(2024, 7, 10);/d1.Print();d2.Init(2024, 1, 1);d2.Print();return 0;
}

4.2 类对象的存储

4.2.1 成员变量和成员函数的存储???

#include<iostream>
using namespace std;class Date
{
public:void Init(int year, int month, int day){_year = year;_month = month;_day = day;}void Print(){cout << _year << "-" << _month << "-" << _day << endl;}
private:int _year;int _month;int _day;};
int main()
{Date d1;Date d2;d1.Init(2024, 7, 10);//使用 . 操作符访问成员对象d1.Print();d2.Init(2024, 1, 1);d2.Print();return 0;
}

上面的代码,透过汇编观察可以发现,类定义的不同对象虽然成员变量不同,就需要各自存储他们;但是调用的成员函数其实是一样的(地址是一样的),如果在每个对象里面都存储一份,就会有空间的重复浪费。(例如:用类实例化出100个对象,每个成员函数都要重复地存储100次,实属浪费!)
QQ截图20240713110850.png
其实,函数指针是不需要存储的。函数指针是一个地址,调用函数被汇编成汇编指令[call地址、jmp指令]。编译器在编译链接时就要找到函数的地址,不是在运行时找;而动态多态是在运行时找的,就需要存储函数地址。——跳转到下面的this指针
总结:

  1. 类定义出的不同对象是各自存储成员变量的。
  2. 通过汇编发现,成员函数是在编译链接时找到函数地址,函数地址存储在一个公共的地方,然后编译成汇编指令[如call地址、jmp指令等]的。
  3. 对象中只存储成员变量,而且函数体中并没有关于不同对象的区分,那么不同对象在调用成员函数Init、Print时,该函数是如何知道应该设置d1对象,而不是设置d2对象呢?——这里就引出了this指针!!!(先跳转学习this指针!)

4.3 类对象的大小

4.3.1 一般类的计算

image.pngimage.png
C++的内存对齐规则和C语言结构体中的内存对齐规则一模一样!
· 第一个成员在与结构体偏移量为0的地址处;
· 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处;
· 注意:对齐数=编译器默认的一个对齐数与该成员大小的较小值;
· VS中默认的对齐数为8;
· 结构体总大小为:最大对齐数(所有变量类型最大者与默认对齐参数取最小)的整数倍;
• 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小;
·就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍;
C语言:自定义类型——结构体(✿༺小陈在拼命༻✿)(这一部分知识可以参考这位优秀博主)
计算A实例化对象的大小:

#include<iostream>
using namespace std;
class A
{
public:void Print(){cout << _ch << endl;}
private:char _ch;int _i;
};
int main()
{A a;cout << sizeof(a) << endl;cout << &a << endl;return 0;
}

运行结果:
image.png
画图分析:
QQ截图20240713110919.png

Q:为什么要内存对齐?
A:CPU读取内存数据时,并不是从任意位置开始读取的,读取与CPU的字长、数据总线有关,
如果CPU可以从任一位置读取,那么内存对齐规则不仅麻烦,还浪费时间。为什么还要有对齐规则呢?
读取数据与数据总线有关,32根数据总线(4Byte,数据总线数量与机器型号有关)----计算机组成原理。规定:从起始点开始,不管数据有多少,CPU一次都读取32个数据,但是这里面也许只有1个数据是CPU真正想读取的。
综合来看,内存对齐规则减少访问次数、提高了CPU的效率。

4.3.2 空类的计算

空类:类中只有成员函数或者什么也没有时,这个类就叫做空类。

//计算⼀下B/C实例化的对象是多⼤?
#include<iostream>
using namespace std;
class B
{
public:void Print(){//...}
};
class C
{};
int main()
{B b;C c;cout << sizeof(b) << endl;cout << &b << endl;cout << sizeof(c) << endl;cout << &c << endl;return 0;
}

运行结果:
image.png
B和C都是空类。首先类对象的大小不能为0,否则不能表示该对象存在过,而且还要通过B对象开空间去实例化呢。因此,C++给空类1Byte的空间用来占位标记这个类的对象的存在,实际操作中的使用性也很少。

五、this指针

5.1 this指针的引入

先观察这段代码:

#include<iostream>
using namespace std;class Date
{
public:void Init(int year, int month, int day){_year = year;_month = month;_day = day;}void Print(){cout << _year << "-" << _month << "-" << _day << endl;}
private://只是生命,没有开辟实际的空间int _year;int _month;int _day;};
int main()
{Date d1;Date d2;d1.Init(2024, 7, 10);//使用 . 操作符访问成员对象d1.Print();d2.Init(2024, 1, 1);d2.Print();return 0;
}

运行结果:
image.png
根据前面 3.2.1 的分析可知,类中的成员函数并没有存储在类的对象中,而且函数体中并没有关于不同对象的区分,那么函数是如何知晓自己应该访问哪个对象的呢?
C++中通过引入this指针解决该问题,即:C++编译器给每个“非静态的成员函数”增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象)(因此,this指针是一个当前类类型的指针,传参就要传入&类名定义的对象名,如 &d1)。
在函数体中所有“成员变量”的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。这个隐藏的指针参数就是this指针。
类的成员函数中访问成员变量,本质都是通过this指针来访问的(编译时编译器自动会处理)。如Init函数中给_year 赋值:this -> _year = year;
加入this指针后的原型代码如下面的注释:

#include<iostream>
using namespace std;
class Date
{
public://原型:void Init(Date* const this, int year, int month, int day)void Init(int year, int month, int day){_year = year;_month = month;_day = day;}//原型:void Print(Date* const this)//const修饰的是thisvoid Print(){cout << _year << "-" << _month << "-" << _day << endl;//原型可以显示写:cout << this -> _year << "-" <<  this -> _month << "-" << this -> _day << endl;}
private:int _year;int _month;int _day;//this->_year = year;原型//this->_month = month;//this->_day = day;//这个this->可以显示地写出来,因为调用函数体中的this指针
};
int main()
{Date d1;Date d2;d1.Init(2024, 7, 10);//原型:d1.Init(&d1, 2024, 7, 10);d1.Print();			 //原型:d1.Print(&d1);d2.Init(2024, 1, 1); //原型:d2.Init(&d2,2024,1,1);d2.Print();			 //原型:d2.Print(&d2);return 0;
}

5.2 this指针的特点

  1. this指针的类型:this指针是一个当前类类型的指针, const ,所以成员函数中,不能给this指针赋值,不能修改this,可以修改this指针指向的内容的;*
  2. this指针本质上是成员函数第一个隐含的指针形参(所以this指针存储在函数栈桢中),当对象调用成员函数时,将对象地址作为实参传递给this形参,所以对象中不存储this指针;(之前计算对象实例化大小的时候都没有计算this指针的大小)
  3. this指针是指针形参,一般情况下都由编译器通过ecx寄存器自动传递,不需要用户和传递;(VS编译器)

image.png

  1. C++规定不能在实参和形参的位置显示的写this指针(编译时编译器会处理),但是可以在函数体内显示使用this指针。(如上面的代码例子)

5.3 Question

5.3.1 Q1

  1. 下面程序编译运行结果是(C.)
  • A.编译报错
  • B. 运行崩溃
  • C. 正常运行
#include<iostream>
using namespace std;
class A
{
public:void Print(){//cout << this << endl;//输出空指针0000000,不会报错,因为没有使用!!cout << "A::Print()" << endl;}
private:int _a;
};
int main()
{A* p = nullptr;//p是一个nullptr指针空值,类型为 A* ,是类类型//mov ecx pp->Print();//call 地址//p->Print(p);//这里不需要取地址!!!//p -> _a = 1;//error这个才是空指针解引用,_a存储在对象里面的(_a是public时)return 0;
}

运行结果:image.pngimage.png???
image.png
**程序正常运行,**分析过程:

  1. 编译器被编译后,底层都是将其转换成汇编指令。p->Print(); 转化的底层汇编是 call 地址,因为成员函数的地址指针不存储在对象里,该地址不在 p 对象里,编译成汇编指令后在符号表里面。
  2. 调用函数需要传递参数,参数传递 this 指针,this是类类型的一个指针,这里不需要取地址,因为 p (实参,它已经是地址了,不用取地址!)就是类类型指针,传递给行参,但是并没有使用该空指针,因此没有空指针报错!p->Print(); 并不是空指针解引用!!
  3. 成员函数并不存放在类对象中,而是存放在公共代码段。虽然我们表面看上去解引用,但实际上编译器不需要通过解引用去找对应函数,只需要去公共代码区执行对应函数即可。因此并不是空指针解引用!

5.3.2 Q2

  1. 下面程序编译运行结果是(B.)
  • A.编译报错
  • B. 运行崩溃
  • C. 正常运行
#include<iostream>
using namespace std;
class A
{
public:void Print(){cout << "A::Print()" << endl;cout << _a << endl;//这里的_a是通过this指针解引用访问的,空指针解引用!!!! }
private:int _a;
};
int main()
{A* p = nullptr;p->Print();//p->_a  = 1;//error,这里就是在类外面访问的,本来是被限制了的return 0;
}

运行结果:
image.png
程序运行崩,过程分析:
访问对应的成员变量,会传递对应对象的地址。而这里的地址为nullptr,通过nullptr->_a引起程序崩溃。

六、 C++和C语言实现Stack对比

6.1 封装

面向对象有三大特性:封装、继承、多态。
封装的概念: 用类将对象的属性(数据)与操作数据的方法结合在一块,让对象更加完善,通过访问权限选择性的将其接口提供给外部的用户使用。
封装本质上是一种管理,让用户更方便使用类。 比如:对于电脑这样一个复杂的设备,提供给用户的就只有开关机键、通过键盘输入,显示器,USB插孔等,让用户和计算机进行交互,完成日常事务。但实际上电脑真正工作的却是CPU、显卡、内存等一些硬件元件。
类也是一样,我们使用类将数据和方法都封装起来。不想对外开放的就用 protected/private 封装起来,用 public 封装的成员允许外界对其进行合理的访问。 所以封装本质上是一种管理。

6.2 C语言实现Stack

//Stack.c
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
typedef int STDataType;
typedef struct Stack
{STDataType* a;int top;int capacity;
}ST;
void STInit(ST* ps)
{assert(ps);ps->a = NULL;ps->top = 0;ps->capacity = 0;
}
void STDestroy(ST* ps)
{assert(ps);free(ps->a);ps->a = NULL;ps->top = ps->capacity = 0;
}
void STPush(ST* ps, STDataType x)
{assert(ps);// 满了, 扩容if (ps->top == ps->capacity){int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;STDataType* tmp = (STDataType*)realloc(ps->a, newcapacity *sizeof(STDataType));if (tmp == NULL){perror("realloc fail");return;}ps->a = tmp;ps->capacity = newcapacity;}ps->a[ps->top] = x;ps->top++;
}
bool STEmpty(ST* ps)
{assert(ps);return ps->top == 0;
}
void STPop(ST* ps)
{assert(ps);assert(!STEmpty(ps));ps->top--;
}
STDataType STTop(ST* ps)
{assert(ps);assert(!STEmpty(ps));return ps->a[ps->top - 1];
}
int STSize(ST* ps)
{assert(ps);return ps->top;
}
int main()
{ST s;STInit(&s);STPush(&s, 1);STPush(&s, 2);STPush(&s, 3);STPush(&s, 4);while (!STEmpty(&s)){printf("%d\n", STTop(&s));STPop(&s);}STDestroy(&s);//s.a[s.top]可以直接访问栈顶元素,但是不规范//但是这种访问方式并不好,万一栈是空栈时,越界!//所以用C语言这样的实现不怎么规范,而且存在风险!!!return 0;
}

6.3 C++实现Stack

//Stcak.cpp
#include<iostream>
using namespace std;
typedef int STDataType;
class Stack
{
public:// 成员函数void Init(int n = 4){_a = (STDataType*)malloc(sizeof(STDataType) * n);if (nullptr == _a){perror("malloc申请空间失败");return;}_capacity = n;_top = 0;}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;}void Pop(){assert(_top > 0);--_top;}bool Empty(){return _top == 0;}int Top(){assert(_top > 0);return _a[_top - 1];}void Destroy(){free(_a);_a = nullptr;_top = _capacity = 0;}
private:// 成员变量STDataType * _a;size_t _capacity;size_t _top;
};
int main()
{Stack s;s.Init();s.Push(1);s.Push(2);s.Push(3);s.Push(4);while (!s.Empty()){printf("%d\n", s.Top());s.Pop();}s.Destroy();return 0;
}

C++中数据和函数都放到了类里面,通过访问限定符进性了限制,不能再随意通过对象直接修改数据,这是C++封装的⼀种体现,这个是最重要的变化。这里的封装的本质是一种更严格规范的管理,避免出现乱访问修改的问题。
想想我们是如何管理陕西省的兵马俑的。我们若什么都不管,兵马俑就被随意破坏了。所以我们建立了一座房子将兵马俑封装起来。但是我们封装的目的不是为了不给别人看,所以我们开放了售票通道,人们可以通过买票突破封装,在合理的监管机制下进去参观。

在这里插入图片描述
创作不易,喜欢的uu记得三连支持一下哦!
在这里插入图片描述
在这里插入图片描述


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

相关文章

OpenCV solvePnP位姿估计

目录 一、概述 二、实现代码 2.1solvePnP函数 2.1.1输入参数 2.1.2输出参数 2.2完整代码 三、实现效果 3.1标定板位姿 3.2标定板到相机的变换矩阵 一、概述 完成相机标定后&#xff0c;可以通过检测标定板在图像中的位置来计算标定板在相机坐标系下的位姿&#xff08;…

vue 项目代码架构

Vue项目的代码架构通常遵循一定的组织结构和约定&#xff0c;以提高项目的可维护性、可扩展性和可读性。以下是对Vue项目代码架构的详细解析&#xff1a; 一、项目目录结构 Vue项目的目录结构通常包括以下几个关键部分&#xff1a; 根目录&#xff1a; package.json&#x…

如何使用这个XMLHttpRequest?

ajax含义:async javascript and XML;是异步的JS和XML&#xff1b;是实现页面局部刷新的技术(是一门独立的技术)。 为什么在js内能够使用呢&#xff1f;是因为ajax在浏览器内内置了一个核心对象&#xff0c;--》XMLHttpRequest&#xff08;低版本的IE浏览器没有&#xff09; 步…

Jetson-AGX-Orin gstreamer+rtmp+http-flv 推拉流

Jetson-AGX-Orin gstreamerrtmphttp-flv 推拉流 Orin是ubuntu20.04 ARM64架构的系统&#xff0c;自带gstreamer 1、 测试摄像头 测试摄像头可以用v4l2-ctl命令或者用gst-launch-1.0 #用v4l2-ctl测试摄像头,有尖角符号持续打印则正常 v4l2-ctl -d /dev/video0 --set-fmt-vid…

MySQL篇:事务

1.四大特性 首先&#xff0c;事务的四大特性&#xff1a;ACID&#xff08;原子性&#xff0c;一致性&#xff0c;隔离性&#xff0c;持久性&#xff09; 在InnoDB引擎中&#xff0c;是怎么来保证这四个特性的呢&#xff1f; 持久性是通过 redo log &#xff08;重做日志&…

暗黑魅力:Xcode全面拥抱应用暗黑模式开发指南

暗黑魅力&#xff1a;Xcode全面拥抱应用暗黑模式开发指南 随着苹果在iOS 13和iPadOS 13中引入暗黑模式&#xff0c;用户可以根据自己的喜好或环境光线选择不同的界面主题。作为开发者&#xff0c;支持暗黑模式不仅能提升用户体验&#xff0c;还能彰显应用的专业性。Xcode提供了…

AI数字人直播saas系统源码分析与解读,哪家部署的系统更具优势?

随着AI数字人直播的应用潜力持续展现&#xff0c;越来越多的创业者都有了打造AI数字人直播saas系统&#xff0c;从而通过为各大企业提供AI数字人直播等服务来获得收益。在此背景下&#xff0c;各大数字人源码厂商所部署的AI数字人直播saas系统源码质量成为了众多创业者的重点关…

概率论原理精解【3】

文章目录 向量值向量值函数导数向量值函数定义性质应用示例 向量值函数的导数定义性质应用 向量值 向量值函数导数 D n ⊂ R n , 向量值函数 f : D n → R m D^n \subset R^n,向量值函数f:D^n\rightarrow R^m Dn⊂Rn,向量值函数f:Dn→Rm 1. 向量值函数 f ( f 1 , f 2 , . . …

外呼系统用回拨模式打电话有什么优势

外呼系统采用回拨模式的优势主要体现在以下几个方面&#xff1a; 1. 提高工作效率 - 回拨模式允许通过一键拨打客户电话&#xff0c;一旦客户接听&#xff0c;即可立即进行沟通&#xff0c;大大缩短了拨号等待时间和无效通话时间。 - 与传统的外呼方式相比&#xff0c;回拨模式…

OSU!题解(概率dp)

题目&#xff1a;OSU! - 洛谷 思路&#xff1a; 设E()表示截止到i所获得的分数&#xff1b; 对于到i点的每一个l&#xff0c;如果第i1点为1&#xff0c;那么会新增分数3*l^23*l1; 就有递推公式方程&#xff1a; E()E()p[i1]p*(3*l^23*l1);(p代表截止到i获得长度l的概率)&a…

策划分销策略中的AI智能名片O2O商城小程序应用探索

摘要&#xff1a;在数字经济时代&#xff0c;企业面临着前所未有的市场竞争压力&#xff0c;传统的分销模式已难以满足快速变化的市场需求。随着人工智能&#xff08;AI&#xff09;技术的不断成熟与移动互联网的普及&#xff0c;AI智能名片O2O商城小程序作为一种新兴的分销工具…

【区块链 + 智慧政务】涉税行政事业性收费“e 链通”项目 | FISCO BCOS应用案例

国内很多城市目前划转至税务部门征收的非税收入项目已达 17 项&#xff0c;其征管方式为行政主管部门核定后交由税务 部门征收。涉税行政事业性收费受限于传统的管理模式&#xff0c;缴费人、业务主管部门、税务部门、财政部门四方处于 相对孤立的状态&#xff0c;信息的传递靠…

http协议,tomcat的作用

HTTP 概念:Hyper Text Transfer Protocol&#xff0c;超文本传输协议&#xff0c;规定了浏览器和服务器之间数据传输的规则。 特点: 1.基于TCP协议:面向连接&#xff0c;安全 2. 基于请求-响应模型的:一次请求对应一次响应 3HTTP协议是无状态的协议:对于事务处理没有记忆能…

原来,BI数据分析也是有模板的

在当今数据驱动的时代&#xff0c;商业智能&#xff08;BI&#xff09;数据分析已经成为企业决策的重要工具。然而&#xff0c;很多人可能并不了解&#xff0c;BI数据分析并非从零开始&#xff0c;而是可以依托现成的模板和解决方案来快速搭建和实施的。以奥威BI方案为例&#…

ARM功耗管理之功耗数据与功耗收益评估

安全之安全(security)博客目录导读 思考&#xff1a;功耗数据如何测试&#xff1f;功耗曲线&#xff1f;功耗收益评估&#xff1f; UPF的全称是Unified Power Format&#xff0c;其作用是把功耗设计意图&#xff08;power intent&#xff09;传递给EDA工具&#xff0c; 从而帮…

Hadoop发展史和生态圈介绍

目录 一、Hdoop概述 二、Hadoop生态组件 三、大数据的技术生态体系 四、Hadoop发展历史 4.1 概述 4.2 Hadoop历史发展节点 4.2.1 2002-2004年理论阶段 4.2.2 2005-2008年Hadoop的问世与崛起 4.2.3 2009-2017年Hadoop助力大数据行业的发展 4.2.4 至今 五、Hadoop优势特…

AWS ECS实现低风险的服务更新:创建新服务和流量切换

在使用Amazon ECS (Elastic Container Service)进行容器化应用部署时,我们经常需要更新服务。但直接更新现有服务可能会带来风险,尤其是在生产环境中。本文将介绍一种低风险的服务更新方法:基于原有服务创建新服务,并逐步切换流量。 方法概述 基于原有ECS服务的配置创建新的服…

【LINUX】pr_info函数开发摸索

1、打印开关可随时控制&#xff0c;开机如果要修改是否打印日志的话&#xff0c;需要修改代码重新编译内核才行&#xff0c;其实如果真要搞&#xff0c;应该有其他方法&#xff1b; 2、打印次数&#xff0c;当前代码里边写的是1000次&#xff0c;其实可以根据传参动态修改打印…

Selenium 元素操作 WebElement 对象

通过 find_element() 方法找到的元素对象就是 WebElement 类型。clear(): 清除文本 send_keys(value): 模拟按键输入 click(): 单击元素 submit()&#xff1a; 提交表单(有些不提供搜索按钮&#xff0c;通过键盘上的回车键完成提交&#xff0c;可以通过 submit 模拟) size: 获…

阿里云Linux中安装MySQL,并使用navicat连接以及报错解决

首先查询是否安装MySQL // linux 使用yum安装或者rpm安装。(就是一个安装工具类似于applStore&#xff0c;brew不必在意) // 区别&#xff1a;yum会自动安装你要安装的东西的其他依赖&#xff0c;rpm不会但会提示你需要安装的东西&#xff0c;比较麻烦&#xff0c;所以采用yum安…