深入解析C++11:现代特性和应用

在这里插入图片描述

目录

  • 一.c++11.简介
  • 二.列表初始化和initializer_list
      • 1.列表初始化
      • 2.initializer_list
  • 三.简化声明
      • 1.auto
      • 2.decltype
  • 四.新增容器
      • 1.array
      • 2.forward_list
      • 3.unordered_map/set
  • 五.右值引用与移动语义
      • 1.左值和右值
      • 2.左值引用
      • 3.右值引用
      • 4.移动构造和移动赋值
      • 5.万能引用和引用折叠
      • 6.完美转发
  • 六.lambda表达式
  • 七.模板可变参数
  • 八.emplace
  • 九.包装器
      • 1.function
      • 2.bind

一.c++11.简介

C++11是C++编程语言的一个重要版本更新,它在2011年被标准化。C++引入了进140个新特性,并且修正的大量的缺陷,使得C++编程更加高效和便捷。

二.列表初始化和initializer_list

1.列表初始化

c++98中,语言给我们提供了可用花括号{}初始化数组和结构体的方法如下所示:
在这里插入图片描述
c++11中则扩大了{}的适用范围,并且在使用时可以不加等号。也可以用在new表达式中
在这里插入图片描述

2.initializer_list

initializer_list是c++11新引入的标准库模板。
在这里插入图片描述

由上图可知initializer_list是一个常量区数组,存放在常量区。
在这里插入图片描述
各大容器也支持了initializer_list的构造
在这里插入图片描述

三.简化声明

1.auto

auto可以帮助我们自动推导变量的类型,在一些复杂的情况下有很大的作用,如下图所示:
在这里插入图片描述
如果这里自己写迭代器类型确实比较麻烦,auto很好的帮助我们解决了这个问题。

2.decltype

decltype 是C++11引入的强大工具,能够查询表达式的类型而不计算表达式的值。在泛型编程、模板编程和类型推断中,decltype
提供了极大的灵活性和类型安全性。通过结合使用 auto 和 decltype,我们可以编写更加简洁、灵活和可维护的代码。

先举个简单的例子窥探他的作用:

int a = 5;
decltype(a) b = 10; // b的类型是int

decltype还经常和auto相结合使用:

int x = 42;
auto y = x;          // y的类型是int
decltype(x) z = y;   // z的类型也是int

在模板时,我们不能明确形参的类型,也可以使用decltype来推导:

template<class T1, class T2>
void F(T1 t1, T2 t2)
{
decltype(t1 * t2) ret;
cout << typeid(ret).name() << endl;
}

decltype 还可以处理更复杂的表达式,推断出嵌套表达式的类型:

struct Example {int value;
};int main() {Example ex;decltype(ex.value) n = 100; // n的类型是intreturn 0;
}

四.新增容器

c++11中又引入了四个新容器:
在这里插入图片描述

1.array

C++11标准引入了std::array容器,这是一个新的数组容器类型,位于头文件中。相比于静态数组,其越界检查更加严格
在这里插入图片描述
如上图所示在越界打印 arr2[6] 时编译器并没有报错而在打印 arr[1] 的时候直接就报错了

2.forward_list

C++11标准引入了forward_list,这是一个单向链表容器,位于头文件<forward_list>中。forward_list提供了高效的插入和删除操作,特别适用于对内存和性能有严格要求的应用场景。

#include <forward_list>
#include <iostream>int main() {std::forward_list<int> flist = {1, 2, 3, 4, 5}; // 声明并初始化一个包含5个整数的单向链表// 输出链表元素for (const auto& elem : flist) {std::cout << elem << " ";}std::cout << std::endl;return 0;
}

总体来说 上面两个新容器是比较鸡肋的

3.unordered_map/set

C++11标准引入了哈希表容器sunordered_map和unordered_set,分别位于头文件<unordered_map>和<unordered_set>中。这些容器提供了高效的元素查找、插入和删除操作,是传统map和set的无序版本,基于哈希表实现。在我们之前在哈希表的学习中就已经了解了。

五.右值引用与移动语义

1.左值和右值

什么是左值和右值?

左值(Lvalue):指向特定内存位置的值,可以出现在赋值运算符的左侧。左值有持久的存储周期,意味着它们在表达式结束后依然存在。

右值(Rvalue):不指向特定内存位置的值,只能出现在赋值运算符的右侧。右值是临时的,在表达式结束后通常会被销毁。

  1. 简单来说左值可以取地址右值不可以。
  2. 左值可以出现在赋值符号的左边而右值不可以出现在左边
  3. 右值也是一个表示数据的表达式,如:字面常量表达式返回值函数返回值(这个不能是左值引用返回)等等
int a = 10;     // 'a' 是左值
int b = a + 5;  // 'a + 5' 是右值

左值举例:

  • 变量名(如 a)
  • 数组元素(如 arr[0])
  • 解引用指针(如 *ptr)
  • 字符串字面值(如 “Hello”)

右值举例:

  • 字面值(如 10, 3.14)
  • 表达式结果(如 a + b)
  • 返回右值的函数调用(如 std::move(x))

2.左值引用

在这里插入图片描述
左值引用就是我们之前说的引用。
const左值可以引用右值:


int main()
{const int& a = 10;return 0; 
}

3.右值引用

右值引用如下所示:

template<class T>
T fmin(T x, T y)
{return x < y ? x : y;
}int main()
{double x = 1.1;double y = 2.1;int&& a = 10;double&& rr2 = x + y;double&& rr3 = fmin(x, y);return 0; 
}

需要注意的是右值时不能取地址的,我们使用右值引用导致右值被存储到特定位置,且可以取到地址,所以我们说右值引用的属性是左值
右值引用可以引用move后的左值:

int main()
{int a = 10;int&& b = move(a);return 0;
}

4.移动构造和移动赋值

C++11引入了移动语义,使得开发者能够高效地转移资源而不是复制它们。移动构造函数和移动赋值运算符是实现这一特性的关键组件,它们通过"移动"资源而不是复制资源,显著提高了程序性能。

  • 移动构造函数:当一个对象被初始化为另一个对象的右值时调用,用于“移动”资源。
  • 移动赋值运算符:当一个对象被赋值为另一个对象的右值时调用,用于“移动”资源。
	string(string&& s):_str(nullptr), _size(0), _capacity(0){cout << "移动拷贝" << endl;swap(s);}string& operator=(string&& s){cout << "移动赋值" << endl;swap(s);return *this;}
  1. 内置类型的右值:纯右值
  2. 自定义类型的右值:将亡值

c++11这里在对连续的拷贝/赋值时做了特殊处理,合多个为一(提升效率),将函数返回识别成右值,方便进行移动拷贝/构造。

  1. 浅拷贝的类不需要实现移动构造,因为没有需要转移的资源,传值拷贝的代价也不大。
  2. 左值引用的价值是减少拷贝,提高效率
  3. 右值引用的价值弥补左值引用没有解决的场景:传值返回

5.万能引用和引用折叠

引用折叠规则定义了在多层引用的情况下,最终的引用类型。以下是引用折叠规则:

1.所有右值引用折叠到右值引用上仍然是一个右值引用。(A&& && 变成 A&&)
2.所有的其他引用类型之间的折叠都将变成左值引用。 (A& & 变成 A&; A& && 变成 A&; A&& & 变成 A&)

C++11引入了一个强大的特性,称为万能引用(Universal Reference),以及引用折叠(Reference Collapsing)规则。这两个特性极大地增强了模板编程的灵活性和性能,尤其在实现泛型函数和容器时。

什么是万能引用?
万能引用是指能够绑定到左值和右值的引用。在模板参数推导中,如果一个函数参数类型是T&&,并且T是一个模板参数,那么这个引用就是一个万能引用

template <typename T>
void func(T&& param); // param 是万能引用

万能引用的主要应用场景是转发函数,即完美转发(Perfect Forwarding)。完美转发使得我们能够编写接受任意参数并将其完美传递给其他函数的模板。

6.完美转发

在模板编程中,有时需要将参数传递给另一个函数,而不改变其原有的类型属性(即保持左值或右值特性)。完美转发通过万能引用(Universal References)和std::forward实现,使得传递的参数保留其本来的引用类型。

下面的案例可以一窥究竟:

#include <iostream>
#include <utility> // forward// 一个简单的函数,用于展示完美转发
void process(int& x) {cout << "Lvalue reference: " << x << endl;
}void process(int&& x) {cout << "Rvalue reference: " << x << endl;
}// 泛型函数,完美转发参数
template <typename T>
void forwarder(T&& arg) {process(forward<T>(arg)); // forward 进行完美转发
}int main() {int a = 42;forwarder(a);           // 传递左值forwarder(42);          // 传递右值forwarder(move(a)); // 传递右值return 0;
}

六.lambda表达式

首先是lambda表达式的格式:
[捕捉列表] (参数列表) mutable -> 返回值 { 函数体 }
捕获列表说明
捕捉列表描述了上下文中那些数据可以被lambda使用,以及使用的方式传值还是传引用。

  • [var]:表示值传递方式捕捉变量var

  • [=]:表示值传递方式捕获所有父作用域中的变量(包括this)

  • [&var]:表示引用传递捕捉变量var

  • [&]:表示引用传递捕捉所有父作用域中的变量(包括this)

  • [this]:表示值传递方式捕捉当前的this指针

参数列表:与普通函数的参数列表一致,如果不需要参数传递,则可以
连同()一起省略

mutable:默认情况下,lambda函数总是一个const函数,mutable可以取消其常量
性。使用该修饰符时,参数列表不可省略(即使参数为空)。

->returntype:返回值类型。用追踪返回类型形式声明函数的返回值类型,没有返回
值时此部分可省略。返回值类型明确情况下,也可省略,由编译器对返回类型进行推
导。
可以根据以下演示代码窥探其使用方法:

int main()
{int a = 0, b = 2;double rate = 2.555;auto add1 = [](int x, int y)->int {return x + y; };auto add2 = [](int x, int y) {return x + y; };auto add3 = [rate](int x, int y) {return (x + y)* rate; };cout << add1(a, b) << endl;cout << add2(a, b) << endl;cout << add3(a, b) << endl;auto swap1 = [add1](int& x, int& y) {int tmp = x;x = y;y = tmp;cout << add1(x, y) << endl;};swap1(a, b);cout << a << " " << b << endl;return 0;
}

在这里插入图片描述
演示案例2:


int main()
{int x = 0, y = 2;auto swap1 = [x, y]() mutable {// mutable让捕捉的x和y可以改变了,// 但是他们依旧是外面x和y的拷贝int tmp = x;x = y;y = tmp;};swap1();cout << x << ' ' << y << endl;// 引用的方式捕捉auto swap2 = [&x, &y](){int tmp = x;x = y;y = tmp;};swap2();cout << x << ' ' << y << endl;int a = 0;int b = 1;int c = 2;int d = 3;const int e = 1;cout << &e << endl;// 引用的方式捕捉所有对象,除了a// a用传值的方式捕捉auto func = [&, a] {//a++;b++;c++;d++;//e++;cout << &e << endl;};func();cout << a << ' ' << b << ' '<< c << ' ' << d << ' ' << e;return 0;
}

在这里插入图片描述
还有些注意事项:

  • 语法上捕捉列表可由多个捕捉项组成,并以逗号分割。
  • 捕捉列表不允许变量重复传递,否则就会导致编译错误。
  • lambda表达式之间不能相互赋值
  • lambda表达式属于匿名对象
  • 可以用typeid看类型(用uuid标识的)
  • 底层是仿函数
  • lambda是个类每次生成的类会用uuid标识

七.模板可变参数

C++11的新特性可变参数模板能够让您创建可以接受可变参数的函数模板和类模板:

// Args是一个模板参数包,args是一个函数形参参数包
// 声明一个参数包Args...args,这个参数包中可以包含0到任意个模板参数。
template <class ...Args>
void ShowList(Args... args)
{}
 //模板可变参数
template <class T  , class ...Args>
void ShowList(T value , Args... args)
{cout << sizeof...(args) << endl;}int main()
{ShowList(1);ShowList(1, 2);ShowList(1, 2, 2.2);ShowList(1, 2, 2.2, string("xxxx"));// ...return 0;
}

运行上述代码我们可以观察参数包中有几个参数:
在这里插入图片描述
在底层如何展开参数包的呢,如下图所示:

// 递归终止函数
template <class T>
void ShowList(const T& t)
{cout << t << endl;
}
// 展开函数
template <class T, class ...Args>
void ShowList(T value, Args... args)
{cout << value <<" ";ShowList(args...);
}
int main()
{ShowList(1);ShowList(1, 'A');ShowList(1, 'A', std::string("sort"));return 0;
}

还有另一种方法可以不使用递归展开,逗号表达式展开参数包

template <class T>
void PrintArg(T t)
{cout << t << " ";
}
//展开函数
template <class ...Args>
void ShowList(Args... args)
{int arr[] = { (PrintArg(args), 0)... };cout << endl;
}
int main()
{ShowList(1);ShowList(1, 'A');ShowList(1, 'A', std::string("sort"));return 0;
}

八.emplace

C++11 引入的 emplace 系列函数为标准库容器带来了显著的改进。与需要先创建对象然后再添加到容器中的 insert 或 push_back 不同,emplace 允许直接在容器内构造对象。这可以通过消除不必要的拷贝或移动操作来提高性能。
看下面的两个代码来看他的作用:

#include <map>
#include <string>
#include <iostream>using namespace std;int main() {map<int, string> myMap;// 使用 emplace 构造并插入一个键值对myMap.emplace(1, "one");// 遍历并打印 map 中的元素for (const auto& pair : myMap) {cout << pair.first << " : " << pair.second << endl;}return 0;
}

九.包装器

1.function

function 是一个通用、多态的函数包装器,它可以存储、复制和调用任何可调用目标。它的常见用法包括回调函数和事件处理器的定义。

用法案例:

#include <iostream>
#include <functional>using namespace std;// 一个简单的函数
void displayMessage(const string& message) {cout << message << endl;
}int main() {// 定义一个 std::function 包装器,包装一个返回 void,参数为 const string& 的函数function<void(const string&)> func = displayMessage;// 使用 std::function 调用被包装的函数func("Hello, std::function!");return 0;
}
template<class F, class T>
T useF(F f, T x)
{static int count = 0;cout << "count:" << ++count << endl;cout << "count:" << &count << endl;return f(x);
}
double f(double i)
{return i / 2;
}
struct Functor
{double operator()(double d){return d / 3;}
};int main()
{// 函数名cout << useF(f, 11.11) << endl;// 函数对象cout << useF(Functor(), 11.11) << endl;// lamber表达式cout << useF([](double d)->double { return d / 4; }, 11.11) << endl;return 0;
}

2.bind

bind 是一个函数适配器,用于创建绑定了特定参数的新函数对象。它允许我们将函数的一部分参数预先绑定,从而简化后续的调用。
bind可改变参数顺序:
在这里插入图片描述


double Plus(int a, int b, double rate)
{return (a + b) * rate;
}double PPlus(int a, double rate, int b)
{return  rate * (a + b);
}class Sub
{
public:int sub(int a, int b){return a - b;}
};class SubType
{
public:static int sub(int a, int b){return a - b;}int ssub(int a, int b, int rate){return (a - b) * rate;}
};int Sub(int a, int b)
{return a - b;
}int main()
{function<int(int, int)> rSub = bind(Sub, placeholders::_2, placeholders::_1);cout << rSub(10, 5) << endl;function<double(int, int)> Plus1 = bind(Plus, placeholders::_1, placeholders::_2, 4.0);function<double(int, int)> Plus2 = bind(Plus, placeholders::_1, placeholders::_2, 4.2);function<double(int, int)> Plus3 = bind(Plus, placeholders::_1, placeholders::_2, 4.4);cout << Plus1(5, 3) << endl;cout << Plus2(5, 3) << endl;cout << Plus3(5, 3) << endl;// double PPlus(int a, double rate, int b)function<double(int, int)> PPlus1 = bind(PPlus, placeholders::_1, 4.0, placeholders::_2);function<double(int, int)> PPlus2 = bind(PPlus, placeholders::_1, 4.2, placeholders::_2);cout << PPlus1(5, 3) << endl;cout << PPlus2(5, 3) << endl;function<double(int, int)> Sub1 = bind(&SubType::sub, placeholders::_1, placeholders::_2);SubType st;function<double(int, int)> Sub2 = bind(&SubType::ssub, &st, placeholders::_1, placeholders::_2, 3);cout << Sub1(1, 2) << endl;cout << Sub2(1, 2) << endl;function<double(int, int)> Sub3 = bind(&SubType::ssub, SubType(), placeholders::_1, placeholders::_2, 3);cout << Sub3(1, 2) << endl;cout << typeid(Sub3).name() << endl;return 0;
}

还有几点需要注意的:
调非静态成员函数前面应该加上&,bind的底层和lambda类似都是仿函数。
不想更改顺序的参数不会影响placeholders:1,2.3…的顺序
在这里插入图片描述

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

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

相关文章

git-工作场景

1. 远程分支为准 强制切换到远程分支并忽略本地未提交的修改 git fetch origin # 获取最新的远程分支信息 git reset --hard origin/feature_server_env_debug_20240604 # 强制切换到远程分支&#xff0c;并忽略本地修改 2. 切换分支 1. **查看所有分支&#xff1a;**…

mount卡住(失败)解决方案

mount -a卡主 第一步确保两边都打开了NFS服务&#xff01;&#xff01;&#xff01;&#xff01; 客户端执行mount -av 查看信息是拒绝服务 查看服务端&#xff1a;showmount -e 192.168.25.168 看提示信息处理&#xff0c;关闭两端的防火钱 遇到这个错误就是服务端不让客户端…

JAVA--SpringCloud

SpringCloud基础 为什么需要spring cloud 单体结构--Monolith 首先请回想一下我们所开发的服务是什么样子的。通常情况下&#xff0c;这个服务所对应的代码由多个项目&#xff08;模块&#xff09;所组成&#xff0c;各个项目会根据自身所提供功能的不同具有一个明确的边界。…

C++类与对象-基础篇

目录 一、什么是类 1.1 语法定义 1.2 访问限定符 1.3 类域 二、类的实例化 2.1 什么是实例化 2.2 类的大小 三、this指针 3.1 引入 3.2 this指针的使用 一、什么是类 1.1 语法定义 class 类名 {}; 说明 类似于C语言中的结构体&#xff0c;括号后分号不能丢类内成员可…

算术运算符用途解析及应用案例

文章目录 常用的算术运算符及其用途&#xff1a;运算符优先级类型转换高级用法 应用案例1. 计算器程序2. 平方根计算3. 计算平均数和标准差4. 货币兑换5. 计算几何6. 动力学模拟7. 数字图像处理8. 金融计算&#xff1a;复利计算 常用的算术运算符及其用途&#xff1a; 算术运算…

前端面试题40(浅谈MVVM双向数据绑定)

MVVM&#xff08;Model-View-ViewModel&#xff09;架构模式是一种用于简化用户界面&#xff08;UI&#xff09;开发的软件架构设计模式&#xff0c;尤其在现代前端开发中非常流行&#xff0c;例如在使用Angular、React、Vue.js等框架时。MVVM模式源于经典的MVC&#xff08;Mod…

软件架构之软件架构概述及质量属性

软件架构之软件架构概述及质量属性 第 9 章&#xff1a;软件架构设计9.1 软件架构概述9.1.1 软件架构的定义9.1.2 软件架构的重要性9.1.3 架构的模型 9.2 架构需求与软件质量属性9.2.1 软件质量属性9.2.2 6 个质量属性及实现 第 9 章&#xff1a;软件架构设计 像学写文章一样&…

前后端如何实现非对称加解密-使用RSA为例讲解!

写在最前面&#xff0c;RSA是一种非对称加密算法&#xff0c;使用不同的公钥和私钥进行加密和解密。 下面是使用RSA进行加密和解密的代码示例&#xff1a; 前端&#xff1a;使用CryptoJS进行RSA加密 在前端JavaScript中&#xff0c;使用jsencrypt库来进行RSA加密&#xff1a…

领夹麦克风哪个品牌好,哪个麦克风好,热门无线麦克风品牌推荐

​无线领夹麦克风是现代沟通的重要工具&#xff0c;它不仅提高了语音交流的清晰度&#xff0c;还展现了使用者的专业形象。随着技术发展&#xff0c;这些麦克风已经变得更加轻便、时尚&#xff0c;易于使用。在各种场合&#xff0c;如演讲、教育和网络直播中&#xff0c;当然&a…

Matplotlib入门

#折线图用来表示数据的变化 plt.plot(x,y) #直方图用来统计连续性数据 无间隔 plt.hist(data数组,组数) #条形图用来统计离散的数组 并且反映其变化 有间隔 plt.bar(x,y,width 0.3) plt.barh(y,x,height 0.3) #散点图用来xy轴之间的联系 趋势 plt.scatter(x,y) #导入p…

重命名文件的方法有哪些?重命名文件的工具有哪些?

在日常的计算机使用过程中&#xff0c;重命名文件是一项常见但至关重要的任务。无论是为了更好地组织文件、修复命名错误&#xff0c;还是简化文件管理流程&#xff0c;掌握正确的重命名方法和工具都能显著提升效率。 本文将探讨多种重命名文件的方法&#xff0c;同时介绍几款高…

解决Invalid or unsupported by client SCRAM mechanisms(dbeaver)

在用工具&#xff08;dbeaver&#xff09;链接Opengauss数据库的时候&#xff0c;报出标题的错误。原因为驱动不正确。 驱动下载地址&#xff1a;https://opengauss.org/zh/download/ 下载完的包 &#xff0c;解压后&#xff0c;里面应该有两个jar 包,使用postgresql.jar dbe…

国产大模型第一梯队玩家,为什么pick了CPU?

AI一天&#xff0c;人间一年。 现在不论是大模型本身&#xff0c;亦或是AI应用的更新速度简直令人直呼跟不上—— Sora、Suno、Udio、Luma……重磅应用一个接一个问世。 也正如来自InfoQ的调查数据显示的那般&#xff0c;虽然AIGC目前还处于起步阶段&#xff0c;但市场规模已…

qmt量化交易策略小白学习笔记第55期【qmt编程之期权数据--获取历史期权列表】

qmt编程之获取期权数据 qmt更加详细的教程方法&#xff0c;会持续慢慢梳理。 也可找寻博主的历史文章&#xff0c;搜索关键词查看解决方案 &#xff01; 感谢关注&#xff0c;咨询免费开通量化回测与获取实盘权限&#xff0c;欢迎和博主联系&#xff01; 获取历史期权列表 …

教师管理小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;教师管理&#xff0c;个人认证管理&#xff0c;课程信息管理&#xff0c;课堂记录管理&#xff0c;课堂统计管理&#xff0c;留言板管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;课程信息…

Postman使用教程【项目实战】

目录 引言软件下载及安装项目开发流程1. 创建项目2. 创建集合(理解为&#xff1a;功能模块)3. 设置环境变量&#xff0c;4. 创建请求5. 测试脚本6. 响应分析7. 共享与协作 结语 引言 Postman 是一款功能强大的 API 开发工具&#xff0c;它可以帮助开发者测试、开发和调试 API。…

java项目总结数据库

1.什么是数据库 用于存储和管理数据的仓库 2.数据库的特点 1.持久化存储数据。确实数据库就是一个文件系统。 2.便于存储和管理数据 3.使用统一的方式操作数据库 --SQL 3.MqSql服务启动 4.登录和退出 这里的ip值IP地址 5.客户端与服务器关系 6.目录结构 7.SQL 1.什么是SQL&…

节点流与处理流:深入解析Java中的IO流

节点流与处理流&#xff1a;深入解析Java中的IO流 1、节点流&#xff08;Node Stream&#xff09;1.1 定义1.2 好处1.3 示例 2、处理流&#xff08;Processing Stream&#xff09;2.1 定义2.2 好处2.3 创建特征2.4 示例 3、总结 &#x1f496;The Begin&#x1f496;点点关注&…

JavaWeb__正则表达式

目录 1. 正则表达式简介2. 正则表达式体验2.1 验证2.2 匹配2.3 替换2.4 全文查找2.5 忽略大小写2.6 元字符使用2.7 字符集合的使用2.8 常用正则表达式 1. 正则表达式简介 正则表达式是描述字符模式的对象。正则表达式用于对字符串模式匹配及检索替换&#xff0c;是对字符串执行…

如何在Vue中实现拖拽功能?

Vue.js是一款流行的JavaScript框架&#xff0c;用于构建用户界面。其中一个常见的需求是在Vue中实现拖拽功能&#xff0c;让用户可以通过拖拽元素来进行交互。今天&#xff0c;我们就来学习如何在Vue中实现这一功能。 首先&#xff0c;我们需要明白拖拽功能的基本原理&#xf…