1.1 字符串类
1.1.1C语言字符串VSC++字符串
C语言中的字符串
- C语言不支持真正意义上的字符串
- C语言用字符串数组和一组函数实现字符串操作
- C语言不支持自定义类型,因此无法获得字符串类型
C++中的字符串
- C++ 直接支持C语言的所有概念
- C++中没有原生的字符串类型
- C++ 标准库提供了string类型
- string 直接支持字符串连接
- string 直接支持字符串的大小比较
- string 直接支持子串查找和提取
- string 直接支持字符串的插入和替换
1.1.2 字符串和数字的转换
- 标准库中提供了相关的类对字符串和数字进行转换
- 字符串流类(sstream) 用于string的转换
- 相关头文件
- istringstream - 字符串输入流
- ostringstream - 字符串输出流
1.1.3 使用方法
- string ===> 数字
istringstream iss("321.12");
double num;
iss>>num;
- 数字===》字符串
ostringstream oss;
oss <<543.21
string s = oss.str();
1.1.4字符串和数字的转换示例
int main()
{
istringstream iss("123.21");
double num;
iss >> num;
cout<< num<<endl;
ostringstream oss;
oss <<"543.21";
string s =oss.str();
cout<<s<<endl;
return 0;
}
1.1.5 字符串循环右移
- 示例
- “abcdefg 循环右移3位后得到efgabcd”
string right_func(const string&s,unsigned int num)
{
string ret;
unsigned int pos;
num = num %s.length();
pos= s.length()-num;
ret = s.substr(pos);
ret += s.substr(0,pos);
return ret ;
}
int main()
{
string s ="abcdefg";
string s2 = right_func(s,3);
cout <<s2<<endl;
return 0;
}
string operator >>(const string&s,unsigned int num)
{
string ret;
unsigned int pos;
num = num %s.length();
pos= s.length()-num;
ret = s.substr(pos);
ret += s.substr(0,pos);
return ret ;
}
int main()
{
string s ="abcdefg";
string s2 = (s>>4);
cout << s2<<endl;
return 0;
}
1.1.6 字符串翻转
- 要求 使用 string 完成
- 示例 “we;tonight,you” ===⇒ “ew;thginot;uoy”
- 提示:
- string 类中提供了成员函数可以查找目标字符的位置
1.2 数组类
1.2.1 类的对象怎样支持数组的下标访问
- 被忽略的事实
- 数组访问符是C、C++中的内循环操作符
- 数组访问符的原生意义是数组访问和指针运算
a[n] <> *(a+n) <> *(n+a) <=====> n[a];
1.2.2 数组访问操作符([])
- 只能通过类的成员函数重载
- 重载函数能且只能使用一个参数
- 可以定义不同参数的多个重载函数
1.2.3数组类的优化
- 下面是部分代码
//数组类中的代码
int & operator[](int index)
{
return m_pointer[index];
}
// 下面这个是常用技巧
IntArray & self()
{
return *this;
}
//在C++中能不使用指针就不使用指针
int main()
{
IntArray* a = IntArray::NewInstance(5); //这个代码可以通过智能指针类来将指针消除
if( a != NULL )
{
IntArray& array = a->self(); //目的是减少指针的使用
cout << "array.length() = " << array.length() << endl;
array[0] = 1;
for(int i=0; i<array.length(); i++)
{
cout << array[i] << endl;
}
}
delete a;
return 0;
}
1.3经典问题三之一
1.3.1问题1
- 什么时候需要重载赋值操作符?
- 编译器是否提供默认的赋值操作?
1.3.2 答案
- 编译器为每个类默认重载了赋值操作符
- 默认的赋值操作符仅仅完成浅copy
- 当需要进行深copy的时候,必须重载复制操作符
- 赋值操作符合copy构造函数有相同的存在意义
一般性原则:重载复制操作符,必须要实现深拷贝
1.3.3 代码示例
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
class Test{
private:
int m_len;
char* m_pointer;
public:
Test(const char * str)
{
m_len = strlen(str);
m_pointer = new char[this->m_len +1];
strcpy(this->m_pointer,str);
}
Test(const Test& obj)
{
this->m_len = obj.m_len;
this->m_pointer = new char[this->m_len+1];
strcpy(this->m_pointer,obj.m_pointer);
}
void print()
{
printf("m_pointer =%s\n",this->m_pointer);
}
~Test()
{
delete[] m_pointer;
}
};
int main()
{
Test t1("zhangsan");
t1.print();
Test t2 =t1;
t2.print();
Test t3("123");
t3 = t1;
return 0;
}
上述代码报错了,下面是报错信息
为啥会这样呢? 原因就是
两个指针指向了同一个内存空间(堆上内存空间),在对象销毁的时候,会调用两次~Test(),结果同一个堆上的内存空间被释放了两次。
- 结论 :
重载复制操作符,必然需要实现深copy!!!
-解决方案
class Test{
private:
int m_len;
char* m_pointer;
public:
Test(const char * str)
{
m_len = strlen(str);
m_pointer = new char[this->m_len +1];
strcpy(this->m_pointer,str);
}
Test(const Test& obj)
{
this->m_len = obj.m_len;
this->m_pointer = new char[this->m_len+1];
strcpy(this->m_pointer,obj.m_pointer);
}
void print()
{
printf("m_pointer =%s\n",this->m_pointer);
}
//修改部分
Test& operator=(const Test&obj)
{
if(this->m_pointer != NULL) delete[] m_pointer;
this->m_len = obj.m_len;
this->m_pointer = new char[this->m_len + 1];
strcpy(this->m_pointer,obj.m_pointer);
return *this;
}
~Test()
{
delete[] m_pointer;
}
};
int main()
{
Test t1("zhangsan");
t1.print();
printf("before operator =\n");
Test t3("123");
t3.print();
printf("after operator =\n");
t3 = t1;
t3.print();
return 0;
}
1.4经典问题三之二
1.4.1问题引出
- 下面的代码有什么问题
string s = "123456";
const char * p = s.c_str();
cout<<p<<endl;
s.append("abcdefg");
cout<<p<<endl;
- 结果为啥不是自己期望的。
1.4.2 问题分析
1.4.3 正确做法
- 正确做法,是用C++的编程思想,而不是C语言和C++ 混合的思想
1.5经典问题三之三
1.5.1 下面代码的输出
#include<iostream>
#include<string>
using namespace std;
int main()
{
//本质是C++和C语言的思想混合开发,导致结果不是预期的那样
const char *p = "123345"; //C
string s =""; //C++
s.reserve(10);
for(int i =0;i<5;i++)
{
s[i] =p[i];
}
if(!s.empty())
{
cout <<s <<endl;
}
return 0;
}
- 没打印内容
1.5.2分析
参考一 :狄泰软件学院C++进阶剖析
参考二 : C++ primer中文版