专门看广告的网站网站建设方案平台架构
news/
2025/10/2 7:44:17/
文章来源:
专门看广告的网站,网站建设方案平台架构,wordpress网站备案号,天津专业网站制作流程优势目录 前言#xff1a;
1.标准库中的string类
1.1 auto和范围for
auto 范围for
1.2 string类常用接口说明
1.string类对象的常见构造
1.3 string类对象的访问及遍历操作
1.4. string类对象的修改操作 1.5 string类非成员函数
2.string类的模拟实现
2.1 经典的string…
目录 前言
1.标准库中的string类
1.1 auto和范围for
auto 范围for
1.2 string类常用接口说明
1.string类对象的常见构造
1.3 string类对象的访问及遍历操作
1.4. string类对象的修改操作 1.5 string类非成员函数
2.string类的模拟实现
2.1 经典的string类问题 2.2 浅拷贝
2.3 深拷贝
2.4 string类实现
3.写时拷贝 前言
C语言中字符串是以\0结尾的一些字符的集合为了操作方便C标准库中提供了一些str系列 的库函数但是这些库函数与字符串是分离开的不太符合OOP的思想而且底层空间需要用户 自己管理稍不留神可能还会越界访问。
1.标准库中的string类 在使用string类时必须包含#include头文件以及using namespace std; 1.1 auto和范围for
auto
1在早期C/C中auto的含义是使用auto修饰的变量是具有自动存储器的局部变量后来这个不重要了。C11中标准委员会变废为宝赋予了auto全新的含义即auto不再是一个存储类型指示符而是作为一个新的类型指示符来指示编译器auto声明的变量必须由编译器在编译时期 推导而得。
2用auto声明指针类型时用auto和auto*没有任何区别但用auto声明引用类型时则必须加
3当在同一行声明多个变量时这些变量必须是相同的类型否则编译器将会报错因为编译器实际只对第一个类型进行推导然后用推导出来的类型定义其他变量。
4auto不能作为函数的参数可以做返回值但是建议谨慎使用
5auto不能直接用来声明数组
#include map
using namespace std;
int main()
{
std::mapstd::string, std::string dict { { apple, 苹果 },{ orange,
橙子 }, {pear,梨} };
// auto的用武之地
//std::mapstd::string, std::string::iterator it dict.begin();
auto it dict.begin();
while (it ! dict.end())
{
cout it-first : it-second endl;
it;
}
范围for
对于一个有范围的集合而言由程序员来说明循环的范围是多余的有时候还会容易犯错误。因此
C11中引入了基于范围的for循环。for循环后的括号由冒号“ ”分为两部分第一部分是范围
内用于迭代的变量第二部分则表示被迭代的范围自动迭代自动取数据自动判断结束。
范围for可以作用到数组和容器对象上进行遍历
范围for的底层很简单容器遍历实际就是替换为迭代器这个从汇编层也可以看到。
2.3 string类的常用接口说明注意下面我只讲解最常用的接口
1. string类对象的常见构造
return 0;
} 范围for
(1)对于一个有范围的集合而言由程序员来说明循环的范围是多余的有时候还会容易犯错误。因此C11中引入了基于范围的for循环。for循环后的括号由冒号“ ”分为两部分第一部分是范围内用于迭代的变量第二部分则表示被迭代的范围自动迭代自动取数据自动判断结束。
(2)范围for可以作用到数组和容器对象上进行遍历
(3)范围for的底层很简单容器遍历实际就是替换为迭代器这个从汇编层也可以看到。
示例
#includeiostream
#include string
#include map
using namespace std;
int main()
{int array[] { 1, 2, 3, 4, 5 };// C98的遍历for (int i 0; i sizeof(array) / sizeof(array[0]); i){array[i] * 2;}for (int i 0; i sizeof(array) / sizeof(array[0]); i){cout array[i] endl;}// C11的遍历for (auto e : array)e * 2;for (auto e : array)cout e endl;string str(hello world);for (auto ch : str){cout ch ;}cout endl;
return 0;
}
1.2 string类常用接口说明
1.string类对象的常见构造 注意 1. size()与length()方法底层实现原理完全相同引入size()的原因是为了与其他容器的接 口保持一致一般情况下基本都是用size()。 2. clear()只是将string中有效字符清空不改变底层空间大小。 3. resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个不 同的是当字符个数增多时resize(n)用0来填充多出的元素空间resize(size_t n, char c)用字符c来填充多出的元素空间。注意resize在改变元素个数时如果是将元素个数 增多可能会改变底层容量的大小如果是将元素个数减少底层空间总大小不变。 4. reserve(size_t res_arg0)为string预留空间不改变有效元素个数当reserve的参 数小于string的底层空间总大小时reserver不会改变容量大小。
1.3 string类对象的访问及遍历操作 1.4. string类对象的修改操作 注意 1. 在string尾部追加字符时s.push_back(c) / s.append(1, c) / s c三种的实现方式差 不多一般情况下string类的操作用的比较多操作不仅可以连接单个字符还可 以连接字符串。 2. 对string操作时如果能够大概预估到放多少字符可以先通过reserve把空间预留 好。 1.5 string类非成员函数 2.string类的模拟实现
2.1 经典的string类问题 上面已经对string类进行了简单的介绍大家只要能够正常使用即可。在面试中面试官总喜欢让 学生自己来模拟实现string类最主要是实现string类的构造、拷贝构造、赋值运算符重载以及析 构函数。大家看下以下string类的实现是否有问题 // 为了和标准库区分此处使用String
class String
{
public:
/*String()
:_str(new char[1])
{*_str \0;}
*/
//String(const char* str \0) 错误示范
//String(const char* str nullptr) 错误示范
String(const char* str )
{
// 构造String类对象时如果传递nullptr指针可以认为程序非
if (nullptr str)
{
assert(false);
return;
}
_str new char[strlen(str) 1];
strcpy(_str, str);
}
~String()
{
if (_str)
{
delete[] _str;
_str nullptr;
}
}
private:
char* _str;
};
// 测试
void TestString()
{
String s1(hello bit!!!);
String s2(s1);
} 说明上述String类没有显式定义其拷贝构造函数与赋值运算符重载此时编译器会合成默认 的当用s1构造s2时编译器会调用默认的拷贝构造。最终导致的问题是s1、s2共用同一块内存空间在释放时同一块空间被释放多次而引起程序崩溃这种拷贝方式称为浅拷贝。 2.2 浅拷贝 浅拷贝也称位拷贝编译器只是将对象中的值拷贝过来。如果对象中管理资源最后就会导致 多个对象共享同一份资源当一个对象销毁时就会将该资源释放掉而此时另一些对象不知道该 资源已经被释放以为还有效所以当继续对资源进项操作时就会发生发生了访问违规。 就像一个家庭中有两个孩子但父母只买了一份玩具两个孩子愿意一块玩则万事大吉万一 不想分享就你争我夺玩具损坏。
所以可以采用深拷贝解决浅拷贝问题即每个对象都有一份独立的资源不要和其他对象共享。父母给每个孩子都买一份玩具各自玩各自的就不会有问题了。 2.3 深拷贝 如果一个类中涉及到资源的管理其拷贝构造函数、赋值运算符重载以及析构函数必须要显式给 出。一般情况都是按照深拷贝方式提供。 2.4 string类实现 能否写好string反映出我们对类和对象知识的理解是否深刻这一块知识如果理解得不够深刻我们的c程序就会经常出现此类问题。为了方便管理我们将string的实现分为3个文件是实现
string.h :
#pragma once
#includeiostream
#includeassert.h
using namespace std;namespace Myobject
{class string{public:typedef char* iterator;typedef const char* const_iterator;string operator(char ch);string operator(const char* str);void append(const char* str);void insert(size_t pos, char ch);void insert(size_t pos, const char* str);void erase(size_t pos, size_t len npos);size_t find(char ch, size_t pos);size_t find(const char* str, size_t pos);string substr(size_t pos, size_t len);string operator(const string s);string(const char* str ){_size strlen(str);_capacity _size;_str new char[_capacity 1];strcpy(_str, str);}string(const string s){_str new char[s._capacity 1];strcpy(_str, s._str);_size s._size;_capacity s._capacity;}void test0_01();void reserve(size_t n);void push_back(char ch);/*string():_str(new char[1] {\0}),_size(0),_capacity(0){}*/iterator begin(){return _str;}iterator end(){return _str _size;}const_iterator begin() const{return _str;}const_iterator end() const{return _str _size;}const char* c_str() const{return _str;}size_t size(){return _size;}size_t capacity(){return _capacity;}char operator[](size_t pos){assert(pos _size);return _str[pos];}const char operator[](size_t pos) const{assert(pos _size);return _str[pos];}~string(){delete[] _str;_str nullptr;_size _capacity 0;}private:char* _str;size_t _size;size_t _capacity;static const size_t npos;};ostream operator(ostream out, const string s);istream operator(istream in, string s);
}string.cpp :
#define _CRT_SECURE_NO_WARNINGS 1
#includestring.hnamespace Myobject
{const size_t string::npos -1;string string::substr(size_t pos, size_t len){assert(pos _size);if (len _size - pos){len _size - pos;}string sub;sub.reserve(len);for (size_t i 0; i len; i){sub _str[pos i];}return sub;}size_t string::find(char ch, size_t pos){assert(pos _size);for (size_t i 0; i _size; i){if (_str[i] ch){return i;}}return npos;}size_t string::find(const char* str, size_t pos){assert(pos _size);const char* ptr strstr(_str pos, str);if (ptr nullptr){return npos;}else{return ptr - _str;}}void string::erase(size_t pos, size_t len){assert(pos _size);if (len _size - pos){_str[pos] 0;_size pos;}else{for (size_t i pos len; i _size; i){_str[i - len] _str[i];}_size - len;}}void string::insert(size_t pos, char ch){assert(pos _size);if (_size _capacity){reserve(_capacity 0 ? 4 : _capacity * 2);}size_t end _size 1;if (end pos){_str[end] _str[end - 1];end--;}_str[pos] ch;_size;}//插入单个字符void string::insert(size_t pos, const char* str){assert(pos _size);size_t len strlen(str);if (len _size _capacity){reserve(len _size 2 * _capacity ? len _size : 2 * _capacity);}size_t end _size len;while (end - 2 pos){_str[end] _str[end - len];end--;}for (int i 0; i len; i){_str[pos i] str[i];}_size len;}void string::append(const char* str){size_t len strlen(str);if (len _size _capacity){reserve(len _size 2 * _capacity ? len _size : 2 * _capacity);}strcpy(_str _size, str);_size len;// _str[_size] \0;}string string::operator(const char* str){append(str);return *this;}void string::reserve(size_t n){if (n _capacity){char* tmp new char[n 1];strcpy(tmp, _str);delete[] _str;_str tmp;_capacity n;}}//扩容void string::push_back(char ch){if (_size _capacity){reserve(_capacity 0 ? 4 : _capacity * 2);}_str[_size] ch;_size;_str[_size] \0;}//尾插string string::operator(char ch){push_back(ch);return *this;}string string::operator(const string s){if (this ! s){delete[] _str;_str new char[s._capacity 1];strcpy(_str, s._str);_size s._size;_capacity s._capacity;return *this;}}ostream operator(ostream out, const string s){for (auto ch : s){out ch;}return out;}istream operator(istream in, string s){char ch;ch in.get();while (ch ! ch ! \n){s ch;ch in.get();}return in;}
}
test.cpp :
#define _CRT_SECURE_NO_WARNINGS 1
#includestring.hnamespace Myobject
{void test_01(){string s1;string s2(hello world);cout s1.c_str() endl;cout s2.c_str() endl;for (int i 0; i s2.size(); i){s2[i] 2;}cout s2.c_str() endl;s2 A;s2 B;string::iterator it s2.begin();while (it ! s2.end()){cout *it ;it;}cout endl;for (auto ch : s2){cout ch ;}cout endl;s2.insert(0, $);for (auto ch : s2){cout ch ;}cout endl;s2.insert(8, %%%%%%%);for (auto ch : s2){cout ch ;}cout endl;s2.erase(8, 100);for (auto ch : s2){cout ch ;}cout endl;/*s2.append(hehe);for (auto ch : s2){cout ch ;}s2 hello;for (auto ch : s2){cout ch ;}*/}void test02(){string s1(hello world);string s2 s1.substr(6, 5);cout s2.c_str() endl;string s3(hello bit);s2 s3;cout s1 endl;cout s2 endl;cin s1;cout s1 endl;}
}
int main()
{Myobject::test02();//Myobject::test_01();return 0;
}
3.写时拷贝 写时拷贝就是一种拖延症是在浅拷贝的基础之上增加了引用计数的方式来实现的。 引用计数用来记录资源使用者的个数。在构造时将资源的计数给成1每增加一个对象使用该 资源就给计数增加1当某个对象被销毁时先给该计数减1然后再检查是否需要释放资源 如果计数为1说明该对象时资源的最后一个使用者将该资源释放否则就不能释放因为还有 其他对象在使用该资源。 本章完。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/924670.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!