1.泛型编程
泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础。
2.函数模板
2.1函数模板概念:函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。
2.2函数模板格式:
template<typename T1,typename T2,…>
2.3函数模板的实例化:
隐式实例化:
让编译器根据实参推演模板参数的实际类型。
显示实例化:在函数名后的<>中指定模板参数的实际类型
int main()
{
int a1 = 10;
double b1 = 20.0;
//显示实例化
Add<int>(a1, b1);
system("pause");
return 0;
}
如果类型不匹配,编译器会尝试进行隐式类型转换,如果无法转换成功编译器将会报错。
STL
是c++标准库的重要组成部分,不仅是一个可复用的组件库,而且是一个包括数据结构与算法的的软件框架
STL六大组件:
空间配置器, 容器, 配接器, 仿函数, 算法, 迭代器
容器:string vector list deque map set multimap mutilset
string 类
- string是表示字符串的字符串类
- 该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作
- string在底层实际是:basic_string模板类的别名,typedef basic_string<char, char_traits, allocator>
string; - 不能操作多字节或者变长字符的序列。
string常用的接口
void Teststring()
{
string s1; //构造空的string类
string s2("hello"); //用c字符串拷贝构造s2
string s3(s2); //用s2拷贝构造s3
}
string类对象的容量操作
resize和reserve的区别
resize(size_t n, char ch):将string中有效字符数改变到n个,多出的字符用ch进行填充。
resize(size_t n):将string中有效字符个数改变到n个,多出的字符用0填充。
1.扩容函数:—只是扩容,不会改变有效元素的个数。
2.reserve(n)只有比当前string类对象底层空间的容量大的情况才会真正的扩容。
3.reserve(n):n小于当前string类对象底层空间时,reserve会忽略本次操作
4.reserve方法一般只会将容量扩大,而不会将空间缩小。
5.string类为了提高性能,在其中管理一个长度为16个字符的数组
vs中string的扩容方式是按照1.5倍方式进行扩容的
push_back:在底层插入期间进行扩容,开辟空间,拷贝元素,释放就空间,如果一边插入,一边开辟空间-------效率太低。
string 采用push_back尾插元素时,如果大概知道存放多少元素,最好提前先将空间给足,然后插入
string的访问及便利操作:
string的三种便利方式:
string s("hello");
//1.for+operator[]
for(size_t i=0;i<size;i++)
cout<<s[i]<<endl;
//2.迭代器
string ::iterator it=s.begin();
while(it!=s.end())
{
cout<<*it<<endl;
++it;
}
string::reverse_iterator rit = s.rbegin();
while(rit != s.rend())
cout<<*rit<<endl;
// 3.范围for
for(auto ch : s)
cout<<ch<<endl;
}
string类对象的修改操作
class string
{
public:
string(const char str = " ")
{
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()
{
std::string s1(“hello,bit”);
std::string s2(s1);
}
说明:
说明:上述string类没有显式定义其拷贝构造函数与赋值运算符重载此时编译器会合成默认的,当用s1构造s2时,编译器会调用默认的拷贝构造。最终导致的问题是,s1、s2共用同一块内存空间,在释放时同一块
空间被释放多次而引起程序崩溃,这种拷贝方式,称为浅拷贝
c++要解决浅拷贝的问题,引进了深拷贝
深拷贝
如果一个类中涉及到资源的管理,其拷贝构造函数、赋值运算符重载以及析构函数必须要显式给出。一般情况都是按照深拷贝方式提供。
深拷贝:给每个对象独立分配资源,保证多个对象之间不会共享资源而造成多次释放,造成程序崩溃问题
string(const char *str = " ")
:_str(new char[strlen(str) + 1])
{
strcpy(_str, str);
}
~string()
{
if (_str)
{
delete[]_str;
_str = nullptr;
}
}
传统版string类的写法:
class string
{
public:
string(const char* str = "")
{
//构造string类对象时,如果传递nullptr指针,认为程序非法,此处断言
if (nullptr == str)
{
assert(false);
return;
}
_str = new char[strlen(str) + 1];
strcpy(_str, str);
}
string(const string& s)
:_str(new char[strlen(s._str)+1])
{
strcpy(_str, s._str);
}
string& operator=(const string& s)
{
if (this != &s)
{
char* pstr = new char[strlen(s._str) + 1];
strcpy(pstr, s._str);
delete[]_str;
_str = pstr;
}
return *this;
}
~string()
{
if (_str)
{
delete[]_str;
_str = nullptr;
}
}
private:
char* _str;
};
现代版string类的写法
class string
{
public:
string(const char* str = "")
{
if (nullptr == str)
str = "";
_str = new char[strlen(str) + 1];
strcpy(_str, str);
}
string(const string& s)
:_str(new char[strlen(s._str) + 1])
{
strcpy(_str, s._str);
}
string& operator=(string s)
{
swap(_str, s._str);
return *this;
}
~string()
{
if (_str)
{
delete[]_str;
_str = nullptr;
}
}
private:
char* _str;
};