c++编程(10)——string

news2024/5/20 4:32:19

欢迎来到博主的专栏——c++编程
博主ID:代码小豪

文章目录

    • <string>
    • string类的接口
      • 构造、析构、与赋值重载
        • 构造函数
        • 赋值重载运算符
      • 元素访问
        • operator[]
      • 容量
      • 修改器
      • 对string对象的操作
      • 迭代器

std::string是定义在c++标准的一个类,定义在标准库<string>中,其由类模板basic_string实例化而来。这一点我们可以在c++手册当中了解到。
在这里插入图片描述
不同的编译器之间对于string类的成员定义并不相同。(比如vs和g++),如果想要看看vs2022当中basic_string模板的源代码,可以在

D:\visual studio\VC\Tools\MSVC\14.35.32215\include

找到string库的源代码,博主这里是将vs安装到了D盘,如果你们安装到了其他位置,可以通过查看vs的属性找到文件位置。
在这里插入图片描述

请原谅博主能力有限,实在是看不懂string库的源代码,关于string类的成员对象有什么,我们可以在vs的调试当中看到
在这里插入图片描述
其成员可分为4个,分别是_buf、_Mysize、_Myres、_Ptr。

_buf是一个存储字符串的缓冲区,其类型是char[16],可最多存储16个字符。存储在栈区间上
_ptr是一个char*类型的指针,指向开辟在堆区的一块内存,当string类的对象存储的字符大于16个时,_buf不会再存储数据,而是改为在_ptr上存储数据
_Mysize是当前的字符个数
_Myres是最大的字符存储个数

当string对象的字符个数超过16个数,存储数据的内存会从buf改为_ptr指向的内存空间,这个空间是开辟在堆区间上的。

std::string s1("0123456789abcdef\0");

在这里插入图片描述
当_Mysize的个数超过_Myres时,string类会进行扩容,这个扩容操作不需要用户手动进行,当然,string类也提供了一个接口让用户手动的扩容,这在后边会讲到。

string类的接口

由于string类的成员对象都是私有权限(private),用户不能访问这些成员,于是c++提供了众多接口函数让用户通过接口对string类的对象进行操作。这些操作可以在c++使用手册当中看到。
c++使用手册

手册当中对string的接口(成员函数与友元函数)分为7大类,分别是:初始化和赋值、迭代器、容量、元素访问、修改器、字符操作和非成员重载函数。涉及的接口多达50几个,想要在这个博客当中这么多就不符合本专栏的目的了。博主这里简单讲解每个大类当中的常用接口。(博主打算在未来开一个新专栏,目的是精讲STL,如果大家想看请多多关注博主哦。)

构造、析构、与赋值重载

想要学会<string>和STL库。那么学习如何看懂c++使用手册是一个重要的步骤,这里我们将结合使用手册的内容对string类的接口进行讲解。

在这里插入图片描述

构造函数

在c++98的标准当中有7种重载形式,c++11新增了两种重载形式,由于c++11标准新增的两个重载不太常用,因此以c++98标准来讲解。

在这里插入图片描述

在这里插入图片描述
在后续的博客当中将不展示手册当中的参数原文,因为同名参数代表的意义基本一致

从使用手册可以看到,string类的拷贝构造函数重载七种,官方还分别给这七种构造方式进行了命名。

(1)empty constructor ——空构造
empty constructor是string的默认构造函数。其作用是构造一个空字符串。

	std::string s1;//空字符串

(4)from c-string constructor——以字符串构造
C-string指的是C语言当中常用的字符串类型,即char*类型的字符串,这类字符串都是以’\0’作为结束标志。该构造会根据传递的C-string来构造string类型的对象。

	std::string s2("hello world");//s2为"hello world";
	std::cout << s2 << std::endl;//打印"hello world"

(2)copy constructor——拷贝构造
在声明string类的对象时,以引用传递的形式,向拷贝构造传递一个string类的引用参数。该对象会拷贝这个引用对象。

	std::string s2("hello world");//string为"hello world";
	std::string s3(s2);//s2作为实参以引用传递的方式调用构造函数,s3会拷贝s2
	std::cout << s3 << std::endl;//打印"hello world"

(3)substring constructor——子串拷贝构造
这个构造函数有三个参数,分别string引用类型的str,size_t的pos和len。其len还存在一个缺省值_npos。

其作用是复制从str当中的pos位置开始,覆盖len个长度的字符的子串。如果len的长度超过了这个str的字符串长度,那么只复制到str的末尾。

缺省_npos是一个常量,其值以为unsigned int类型的最大值,即2的32次方-1.约等于42亿。

显然一个字符串不应该有这么多的字符个数。因此这个缺省值的意义在于,拷贝从pos位置开始复制,直到str的末尾。

std::string s4("hello world");//string为"hello world";
std::string s5(s4, 0, 5);
//拷贝s4当中从0位置开始的后5个字符,为"hello"
std::string s6(s4, 5);
//利用了_npos这个常量,那么s6会拷贝s4的从第6个字符开始,直到末尾的这部分。为" world"
cout << s5 << endl;//"hello"
cout << s6 << endl;//" world"

(5)以字符数组构造

将s指向的数组的前n个字符拷贝到string类的对象当中。


	char buf[] = "123456789";
	std::string s7(buf, 5);//拷贝buf的前五个字符即"12345"
	cout << s7 << endl;//"12345"

(6)填充字符构造

向string类的对象填充n个字符c。

	std::string s8(3, 'x');//向s8填充3个'x'
	cout << s8 << endl;//"xxx"

(7)范围构造

范围构造会用到string类的迭代器,由于还没有对迭代器进行讲解,这部分内容将会放在下文。

string类的析构函数并不需要用户手动调用——当然你可以试试,而且string类只存在一个析构函数,这个析构函数的作用是将string开辟的堆区空间进行释放。

赋值重载运算符

赋值重载的意义在于,可以让对象之间,也能用赋值操作符(=),完成对象的赋值操作。string类将赋值运算符‘=’重载了3种形式

在这里插入图片描述
(1)string对象可以可以赋值给string对象

	std::string str1("hello world");
	std::string str2;
	str2 = str1;//str2的字符串内容变成了"hello world"
	cout << str2 << endl;//"hello world"

(2)可以用char*类型指针指向的字符串(C-string)赋值给string对象

const char* ptr = "hello world";//C-string
	std::string str3;
	str3 = ptr;//ptr指向的C-string赋值给str3
	cout << str3 << endl;//"hello world"

(3)可以用单个字符赋值给string对象

	std::string str4("hello world");
	str4 = 'a';//字符'a'替换了str4中的内容,str的字符串长度也变为了1
	cout << str4 << endl;//'a'

元素访问

在这里插入图片描述
此类接口使用最多就是下标重载函数了(operator []),在此之间,我们简单的了解一下其余三个函数。

char& at (size_t pos);
const char& at (size_t pos) const;

at函数是返回string当中pos位置的字符的引用,注意pos不能超过字符串长度。

std::string str1("hello world");
cout << str1.at(0) << endl;//打印第一个
str1.at(5) = ',';//str1的第6个字符被修改
cout << str1 << endl;//"hello,world"

back()和front()就是取得字符串串尾和字符串串头的引用,这里就不多介绍了,感兴趣的读者可以查阅c++使用手册。

operator[]

char& operator[] (size_t pos);
const char& operator[] (size_t pos)const;

string类重载了下标访问符号([]),这使得访问string对象的字符元素像访问数组元素一样,比如:
在这里插入图片描述

	std::string str1("hello world");
	for (size_t i = 0; i < 11; i++)
	{
		cout << str1[i] << endl;
	}

可以用下标的形式,遍历整个字符串

容量

容量类的接口通常都是获取string类的成员对象,或者是提供修改成员函数的函数。

在这里插入图片描述
我们挑拣常用的说明

size()

size_t size() const;

ize
size()没有参数,size的返回值是返回当前有效字符的字符串长度(不计入‘\0’),即string的成员对象(_Mysize)。

在遍历string的成员时,可以用到size()。

	std::string s1("hello world");

	for(size_t i=0;i<s1.size();i++)
	{
		cout << s1[i];
	}

lenth()
在这里插入图片描述
lenth()的作用和size()是一样的。

empty()
在这里插入图片描述
empty()用来判断string对象是否是一个空字符,如果是空字符则返回true,反之返回false。

clear()
在这里插入图片描述
celar()会清除string对象的所有字符。

这一类的接口基本没有参数,其作用大多是让用户对string对象的成员_Mysize进行操作,或者是堆string对象的状态进行修改。

修改器

在这里插入图片描述

string的接口非常冗余,在修改器这一模块更加明显,比如operator+=,append,push_back的作用是重叠的,assign、insert、replace也有重叠,pop_back和erase是也是重叠的。所以学会使用c++手册学习STL比看博主的任何相关博客都要重要。

push_back()

其函数原型为:

void push_back (char c);

push_back()会在string对象的字符串末尾插入一个字符C。

std::string s1;
s1.push_back('a');
s1.push_back('b');
s1.push_back('c');
cout << s1 << endl;//"abc"

pop_back()

void pop_back();

pop_back()删除string对象的末尾字符。

std::string s2("abc");//"abc"
s2.pop_back();
cout << s2 << endl;//"ab"

swap()

void swap (string& str);

swap()会将string对象的字符串与str的字符串进行交换。注意,这个swap是string类的成员函数,在c++标准库中还存在一个swap,这是一个函数模板,不要用混咯。

std::string str1("abc");//"abc"
std::string str2("def");//"def"
str1.swap(str2);//str1是调用这个函数的对象
cout << str1 << endl;//"def"
cout << str2 << endl;//"abc"

operator +=
string将+=操作进行了重载,使得string对象可以使用+=符号进行字符或字符串的追加。

string (1)	
string& operator+= (const string& str);
c-string (2)	
string& operator+= (const char* s);
character (3)	
string& operator+= (char c);

可追加的类型有三种,分别是string类型的对象字符串,C-string,和字符。

	std::string str3("hello");
	std::string str4("world");
	str3 += str4;
	cout << str3 << endl;//"helloworld"

	str3 += "123";
	cout << str3 << endl;//"helloworld123"

	str3 += '?';
	cout << str3 << endl;//"helloworld123?"

用+=来追加字符串还是非常好用的,其优点在于程序可读性高,操作简单,灵活。

append()
append的操作除去和opeartor+=重叠的部分,还多了几个,这里就讲讲多出的追加操作。
在这里插入图片描述

substring(2)
string& append (const string& str, size_t subpos, size_t sublen = npos);

string类型的对象在末尾追加str的子字符串,这个子字符串是str从subpos的位置开始,向后覆盖sublen个长度的字符串(如果sublen个长度超过了str的末尾,那么只会覆盖到str的末尾)。

std::string str5("xxx");
std::string str6("0123456789");
str5.append(str6, 3, 5);
cout << str5 << endl;//"xxx34567"
buffer(4)
string& append (const char* s, size_t n);

追加字符数组s的前n个字符。要注意数组越界这个问题。

char buffer[] = "hello world";
std::string str7;
str7.append(buffer, 5);
cout << str7 << endl;//"hello"
fill (5)	
string& append (size_t n, char c);

向string对象追加n个字符c。

std::string str8("aaa");
str8.append(3, 'b');
cout << str8 << endl;//"aaabbb"

对string对象的操作

博主写到这已经很疲惫了,因为相比较于STL的其他容器,string冗余的操作是在是太多了(严格的说string不在STL当中,string库出现的比STL要早,是c++探索泛型编程的过程中出现的不成熟产物。因此在接口的设计方面存在不够简洁的问题),不仅博主写的很烦,估计读者看着也很烦了吧,所以剩余部分的内容博主只会找具有非常不相似性的接口进行说明。

在这里插入图片描述
为什么说相似性高的不再讲解呢?我们拿这个substr举例。这是substr的原型

string substr (size_t pos = 0, size_t len = npos) const;

我甚至不用打开c++手册都能才substr()这个接口的作用。因为pos和len这两个参数贯穿了整个类的成员函数。

其作用为,生成一个子字符串,这个子字符串是string对象的字符串从pos位置开始,贯穿len个长度的字符的拷贝。

这个模块当中的c_str()很值得讲讲。
在这里插入图片描述
c_str会返回一个char*类型的指针,这个指针指向的是string对象当中有效字符串的拷贝。

	std::string str1("hello world");
	char buf[12] = { 0 };
	
	strcpy(buf, str1.c_str());
	cout << buf << endl;//"hello world"

要注意,c_str并不是将string类型的对象进行了类型转换(虽然作用很类似)。string类型的对象也不支持类型转换成C-string类型(即char*,const char*)。随着string对象的使用,_str返回的指针的值可能会改变,因此不要用const char*类型的指针来接收。

在这里插入图片描述
这6个接口均是对字符串内容的索引,我们以find和find_first_of为例。

string (1) size_t find (const string& str, size_t pos = 0) const;
c-string (2) size_t find (const char* s, size_t pos = 0) const;
buffer (3) size_t find (const char* s, size_t pos, size_t n) const;
character (4) size_t find (char c, size_t pos = 0) const;

find重载了4中函数,分别是对string对象的索引,对字符指针s指向的字符串索引,对字符数组的索引,和对字符的索引。pos指的是调用此函数的对象开始查找的位置。

返回字符串中搜索由其参数指定的序列的第一此出现的位置。
当指定pos时,搜索只包括位置pos或位置pos之后的字符。

std::string str1("123456789");
std::string str2("345");

str1.find(str2);//返回4
str1.find("345");//返回4
str1.find('3');//返回4
//4是str1第一次出现这个字符串或字符的位置

在这里插入图片描述

find_first_of和find的区别在于,find是严格按照传入的参数进行查找的,比如“12345”,只有string对象存在“12345”才会返回这个位置。而find_first_of()只会查找传入字符串或者字符当中匹配的一个字符,只要string对象存在符合的任意字符就会返回这个位置。

int main ()
{
  std::string str ("Please, replace the vowels in this sentence by asterisks.");
  std::size_t found = str.find_first_of("aeiou");
  while (found!=std::string::npos)
  {
    str[found]='*';
    found=str.find_first_of("aeiou",found+1);
  }

  std::cout << str << '\n';

  return 0;
}

这段代码会将字符串中的aeiou字符,全部替换成*。

迭代器

迭代器是c++泛型编程又一重大产物,如同它的名字,迭代器的作用是用来遍历泛型容器中的元素。

我们可以简单的认为迭代器是一个指针(至少string当中他是这样的),我们可以通过++,–让迭代器指向下一个元素。也可以让迭代器通过算术加减访问前n个或后n个元素(和指针性质一致)。甚至还能用解引用操作符(*),来读写这个元素。

在string中,我们有6个接口来获取string对象的迭代器。
在这里插入图片描述
begin()用来获取字符串的起始元素,end()用来获取字符串的末尾元素。
在这里插入图片描述
既然被称为迭代器了,那么它肯定是支持遍历整个字符串的。

	std::string str1("hello world");
	for (std::string::iterator it1 = str1.begin();
		it1 != str1.end();
		it1++)
	{
		cout << *it1;
	}

string迭代器分为4中类型,分别为

(1)iterator
(2)const_iterator
(3)reverse_iterator
(4)const_recerse_iterator

iterator就是最基本的迭代器类型,string当中的迭代器我们可以认为是这种类型的

typedef char* iterator;//vs的实现不是这样!!博主只是为了方便理解

因此我们可以用const修饰迭代器,若是如此操作,那么迭代器就不能修改指向的位置。但是可以修改指向的数据。

std::string str1("hello world");
const std::string::iterator it1 = str1.begin();
it1++;//error,被const修饰的迭代器不能修改指向的位置
*it1 = 'j';//可以修改指向的位置

实际上很好理解,因为const iterator可以等价为char* const。当const修饰的是指针时,指向的位置是只读不写的,所以不能执行++操作。

如果是想让迭代器指向的数据只读不写,那就要用到const_iterator了。用const_iterator类型的迭代器,其指向地数据的权限是只读不写的。类似于const char*

	std::string str1("hello world");
	std::string::const_iterator it1 = str1.begin();
	it1++;//const_iterator类型的迭代器修改指向的位置
	*it1 = 'j';//error,指向的数据是只读不写的

如果想让迭代器不改变指向的位置,也不能修改数据,那么就用
const const_itearator修饰就行

reverse_iterator是为了支持反向迭代而建立的(string当中反向迭代的意义不大,但是其他容器是有反向迭代的场景的)
在这里插入图片描述
在这里插入图片描述
rbegin和rend就是提供给反向迭代器的接口,rbegin指向字符串尾,rend指向字符串口。
在这里插入图片描述
有趣的是,reverse_iterator也支持++和–以及算术加减运算。但是执行的效果却是与iterator相反的。如果iterator++是指向下一个元素,那么reverse_iterator++则是指向上一个元素,这也就是为什么说,迭代器像指针,但却不完全是指针,因为指针不会出现++是指向上一个元素这种操作。

  std::string str2("hello world");
	for (std::string::reverse_iterator rit1 = str2.rbegin();
	 rit1 != str2.rend();
	  rit1++)//倒着遍历str2
	{
		cout << *rit1;
	}

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

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

相关文章

【JavaEE初阶系列】——Servlet运行原理以及Servlet API详解

目录 &#x1f6a9;Servlet运行原理 &#x1f6a9;Servlet API 详解 &#x1f393;HttpServlet核心方法 &#x1f393;HttpServletRequest核心方法 &#x1f388;核心方法的使用 &#x1f534;获取请求中的参数 &#x1f4bb;query string &#x1f4bb;直接通过form表…

如何更好地使用Kafka? - 事先预防篇

要确保Kafka在使用过程中的稳定性&#xff0c;需要从kafka在业务中的使用周期进行依次保障。主要可以分为&#xff1a;事先预防&#xff08;通过规范的使用、开发&#xff0c;预防问题产生&#xff09;、运行时监控&#xff08;保障集群稳定&#xff0c;出问题能及时发现&#…

【自动驾驶|毫米波雷达】初识毫米波雷达射频前端硬件

第一次更新&#xff1a;2024/5/4 目录 整体概述 混频器&#xff08;MIXER&#xff09; 低通滤波器&#xff08;LPF&#xff1a;Low-Pass filter&#xff09; 数模转换器&#xff08;ADC&#xff1a;Analog to Digital Converter&#xff09; 毫米波雷达功能框图 整体概述 完…

分布式与一致性协议之ZAB协议(六)

ZAB协议 成员发现 成员发现是通过跟随者和领导者交互来完成的&#xff0c;目标是确保大多数节点对领导者的关系没有异议&#xff0c;也就是确立领导者的领导地位。成员发现的实现流程如图所示。 1.领导者选举结束&#xff0c;节点进入跟随者状态或者领导者状态后&#xff0…

微软 AI 研究团队推出 SIGMA:一个开源研究平台,旨在推动混合现实与人工智能交叉领域的研究与创新

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

YzmCMS 7.0任意函数调用RCE 漏洞研究分析

YzmCMS是一款基于YZMPHP开发的一套轻量级开源内容管理系统,YzmCMS简洁、安全、开源、免费,可运行在Linux、Windows、MacOSX、Solaris等各种平台上,专注为公司企业、个人站长快速建站提供解决方案。 YzmCMS 某些接口调用了 db_pdo类的where方法 导致了远程命令执行漏洞&#xf…

PLC学习笔记

PLC学习笔记 前言一、一些基操知识二、GX works2编程2.1 位逻辑1.2 中间寄存器1.3 PLC的扫描方式 总结 前言 我这个人真的是太渴望知识了~ 一、一些基操知识 一般X表示输入&#xff0c;Y表示输出。一般八个为一组X0~X7M表示中间寄存器&#xff0c;M0~M7时间T、计数C 二、GX …

操作系统:线程相关知识

目录 1.生产消费者模型 1.1.概念引入 1.2.基于阻塞队列的生产消费模型 1.3.POSIX信号量 1.3.1.再识信号量 1.3.2.信号量接口的学习 1.4.基于环行队列的生产消费模型 1.5.深刻理解生产消费模型 2.可重入函数与线程安全 1.生产消费者模型 1.1.概念引入 生产者-消费者模型…

AI换脸免费软件Rope中文汉化蓝宝石版本全新UI界面,修复部分已知错误【附下载地址与详细使用教程】

rope蓝宝石版&#xff1a;点击下载 注意&#xff1a;此版本支持N卡、A卡、CPU&#xff0c;且建议使用中高端显卡&#xff0c;系统要求win10及以上。 Rope-蓝宝石 更新内容&#xff1a; 0214版更新&#xff1a; ①&#xff08;已修复&#xff09;恢复到以前的模型荷载参数。有…

Hadoop3:HDFS的架构组成

一、官方文档 我这里学习的是Hadoop3.1.3版本&#xff0c;所以&#xff0c;查看的也是3.1.3版本的文档 Architecture模块最下面 二、HDFS架构介绍 HDFS架构的主要组成部分&#xff0c;是一下四个部分 1、NameNode(NN) 就是Master节点&#xff0c;它是集群管理者。 1、管…

Stack数据结构设计模板

第三章 栈、队列、数组 1.栈 1.1 顺序栈 #define MaxSize 20 typedef int ElemType; //顺序栈的定义 typedef struct {ElemType data[MaxSize];int top; }SqStack; // 初始化顺序栈 void InitSqStack(SqStack &S){S.top -1; }; // 入栈(增) bool Push(SqStack &S,El…

RabbitMQ之消费者并发消费

为什么要引入消费者的并发消费&#xff1f; 当生产者的推送速度是远远超过消费者的能力的&#xff0c;可以提高消费者的消费速度。比如在java中我们可以启动多个 JVM 进程&#xff0c;实现多进程的并发消费&#xff0c;从而加速消费的速度&#xff0c;在mq中也可以通过设置配置…

Git系列:Git Stash临时保存与恢复工作进度

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

python从0开始学习(五)

目录 前言 1、顺序结构 2、选择结构 2.1双分支结构 2.2多分枝结构 2.3嵌套使用 2.4多个条件的链接 总结 前言 在上篇文章中&#xff0c;我们学习了python中的运算符&#xff0c;本篇文章继续往下讲解。本篇文章主要讲解程序的组织结构。 1、顺序结构 顺序结构是程序按照…

UDP通讯的demo

udp通讯的demo&#xff0c;这个只是简单的实现。 后面我还会加入udp组播功能。 因为懒&#xff0c;所以我自己发&#xff0c;自己接收了。 经过测试&#xff0c;可以看到&#xff0c;发送消息和接收消息功能都没问题。 广播&#xff1a; 这个是点对点的通过对方的ip和端口发…

设计模式学习笔记 - 回顾总结:在实际软件开发中常用的设计思想、原则和模式

概述 本章&#xff0c;先来回顾下整个专栏的知识体系&#xff0c;主要包括面向对象、设计原则、编码规范、重构技巧、设计模式五个部分。 面向对象 相对于面向过程、函数式编程&#xff0c;面向对象是现在最主流的编程范式。纯面向过程的编程方法&#xff0c;现在已经不多见了…

网络网络层之(4)IPv4协议

网络网络层之(1)IPv4协议 Author: Once Day Date: 2024年4月4日 一位热衷于Linux学习和开发的菜鸟&#xff0c;试图谱写一场冒险之旅&#xff0c;也许终点只是一场白日梦… 漫漫长路&#xff0c;有人对你微笑过嘛… 全系列文档可参考专栏&#xff1a;通信网络技术_Once-Day的…

设置 kafka offset 消费者位移

文章目录 1.重设kafka消费者位移2.示例2.1 通过 offset 位置2.2 通过时间2.3 设置到最早 1.重设kafka消费者位移 维度策略含义位移Earliest把位移调整到当前最早位移处位移Latest把位移调整到当前最新位移处位移Current把位移调整到当前最新提交位移处位移Specified-Offset把位…

奥威-金蝶BI现金流量表模板,可借鉴、可套用

企业现金流一旦出了问题都是大问题&#xff0c;会直接影响到企业的日常运作&#xff0c;甚至直接关系到企业能不能继续存活&#xff0c;因此现金流量表是企业财务分析中重要报表之一&#xff0c;也是企业监控财务监控情况的重要手段之一。那么这么重要的一份现金流量表该怎么做…

Angular中创建和使用服务

Angular中的服务 文章目录 Angular中的服务前言一、创建服务二、使用服务 前言 Angular 服务是 Angular 应用程序中用于封装可重用逻辑的类。服务在应用程序的多个组件之间共享数据和功能&#xff0c;而不依赖于应用程序的UI。服务可以用于诸如数据处理、与后端通信、用户身份…