Qt中的容器和STL没有多大的区别,只是方法接口上有些不同。只列举几个容器,需要的可以了解的查查文档
QStack
// 概念都是一样的
QStack<int> em;
em.push(1); // 添加元素至栈顶
em.pop(); // 从栈中删除顶部元素并返回它
em.top(); // 仅仅返回对栈顶元素的引用
....
QQueue
QQueue<int> em1;
em1.enqueue(1); // 添加元素到队尾
em1.head(); // 返回对队列首项的引用
em1.dequeue(); // 移除队列中的首项并返回
....
QList
QList<QString> list;
list << "aa" << "bb" << "cc"; // qt中插入元素可以采用<<
list.replace(2,"bc"); // 替换函数,将cc换为bc
list.append("dd"); // 在列表尾部添加
list.prepend("mm"); // 在列表头部添加
QString str = list.takeAt(2); // 在列表中删除第三个项目,并获取它
list.insert(2,"mm"); // 在位置2插入项目
list.swapItemsAt(1,3); // 交换元素1和元素3
list.contains("mm"); // 列表中是否包含"mm"
list.count("mm"); // 列表中mm的个数
list.indexOf("mm"); // 返回第一个匹配的位置
list.indexOf("mm",2); // 也可以指定从哪个索引开始查找
索引数据同STL一样,采用[]和at()方式
QMap
QMap<QString,int> map;
map["one"] = 1; // 插入("one",1);
map.insert("seven",7); //采用insert函数进行插入
int value1 = map["six"]; // 获取键的值,采用[]操作符,如果map中没有该键,那么会自动插入
int value2 = map.value("five"); // 使用value()函数获取键的值,采用函数当不存在时不会自动插入
int value3 = map.value("nine",9); // 当键不存在时,value默认返回0,这里可以设定该值,如这里设定为9
map.insert("ten",10);
map.insert("ten",100); // map一个键对应一个值,如重新给键赋值会覆盖先前的值
// 可以使用*操作符返回一个项目,然后使用key()和value()来分别获取键和值
QMap<QString,int>::const_iterator p;
for(p = map.constBegin();p != map.constEnd()l ++p){
qDebug() << p.key() << ":" << p.value();
}
QMultiMap
// 可以采用QMultiMap来实现一键多值
QMultiMap<QString,int> map1,map2,map3;
map1.insert("values",1);
map1.insert("values",2);
map2.insert("values",3);
map3 = map2 + map1; // 可以进行相加,map3的values将包含2,1,3
QList<int> myValues = map3.values("values");
for(int i = 0;i < myValues.size();++i){
qDebug() << myValues.at(i);
}
需要注意的是,容器可以嵌套! 如QMap<QString,QList >这里的"> >“符号之间是有一个空格,不然编译器会将它当作”>>" 操作符对待。
遍历容器
Qt的容器类提供了两种类型的迭代器,Java风格迭代器和STL风格迭代器。实际当中使用STL风格迭代器更好点,因为它的效率更高,而且可以和Qt,STL的通用算法一起使用(只码STL的感兴趣的可以查查看)。
#include <QList>
QList<QString> list;
list << "A" << "B" << "C" << "D";
QList<QString>::iterator i; // 读写迭代器
for(i = list.begin();i != list.end();++i){
*i = (*i).toLower(); // 转换为小写
qDebug() << *i;
}
QList<QString>::const_iterator j; // 只读迭代器
qDebug() << "the forward is:";
for(j = list.constBegin();j!= list.constEnd();++j){
qDebug() << *j;
}
Qt容器常用的STL算法
#include <algorithm>
QStringList list;
list << "one" << "two" << "three";
QList<QString> list1(3);
std::copy(list.begin(),list.end(),list1.begin()); // 将list中元素复制到list1中
bool ret1 = std::equal(list.begin(),list.end(),list1.begin()); // 将list和list1的元素逐个比较,全部相同则返回true
QList<QString>::iterator i = std::find(list.begin(),list.end(),"two"); // 找到返回对应值的迭代器,否则返回end()
std::fill(list.begin(),list.end(),"eleven"); // 将list中的所有所有项目填充为eleven
QList<int> list2;
list2 << 3 << 3 << 6 << 6 << 6 << 8;
int countsum = std::count(list2.begin(),list2.end(),6); // 查找6的个数
std::sort(list2.begin(),list2.end()); // 使用快速排序算法对list2进行升序排序
std::reverse(list2.begin(),list2.end()); // 反转容器内指定范围的所有元素
std::stable_sort(list2.begin(),list2.end()); // 使用稳定排序算法对list2进行升序排序,如排序前在前的元素,有相同的元素时,在前的元素还是在前,如12,12
QString
#include <QStringList>
QString str = "hello";
str[0] = QChar('H'); // 将第一个字符换为H
str.append(" Qt"); // 向字符串后添加Qt
str.replace(1,4,"i"); // 将第1个字符开始的后面4个字符替换为字符串"i"
str.insert(2,"my"); // 在第2个字符后插入" my"
str = str + "!!!"; // 两个字符串结合
str1 = " hi\r\n Qt! \n ";
QString str2 = str1.trimmed(); // 除去字符串两端的空白字符
str2 = str1.simplified(); // 出去字符串两端和中间多余的空白字符
str = "hi,my,,Qt";
QStringList list = str.split(",",Qt::SkipEmptyParts); //从字符串中有,的地方将其分为多个子字符串
str = list.joni(" "); // 将各个子字符串组合为一个字符串,中间用" "隔开
QString().isNull(); // true
QString().isEmpty(); // true
QString("").isNull(); // false
QString("").isEmpty(); // true
// QString中一个null字符串和一个空字符串并不是完全一样的,一个null字符串是使用QString的默认构造函数或者在构造函数中传递了0来初始化的字符串,一个空字符串是指大小为0的字符串。一般null字符串都是空字符串,但一个空字符串不一定是一个null字符串,一般使用isEmpty()来判断一个字符串是否为空。
// 查询
str = "yafeilinux";
str.right(5); // 右侧5个字符
str.left(5); // 左侧5个字符
str.mid(2,3); // 包含第2个字符以后3个字符的子字符串
str.indexOf("fei"); // 结果为2
str.at(0); // 结果为y
str.count('i'); // 结果为2
str.startsWith("ya"); // 判断str是否以ya开始
str.endsWith("linux"); // 判断str是否以linux结尾
str.contains("lin"); // str是否包含lin字符串
QString temp = "hello";
if(temp > str)
qDebug() << temp;
else
qDebug() << str; // 结果为输出str
// 转换
str = "100";
str.toInt(); // 转换为100
int num = 45;
QString::number(num); // 结果为"45"
str = "123.456";
str.toFloat(); // 结果为123.456
str = "abc";
str.toUpper(); // 结果为ABC
str = "ABC";
str.toLower(); // 结果为abc
int age = 25;
QString name = "yafei";
str = QString("name is %1,age is %2").arg(name).arg(age); // name代替%1,age代替%2
str = " % 1 % 2";
str.arg("% 1f","hello"); // 结果为% 1f hello
str.arg("% 1f").arg("hello"); // 结果为hellof % 2
隐式共享
隐式共享称为写时复制。使用隐式共享类的对象作为参数传递是既安全又有效的,只有一个指向该数据的指针被传递了,只有当函数向它写入时才会复制该数据。
QPixmap p1,p2;
p1.load("image.bmp");
p2 = p1; // p1与p2共享数据
QPainter paint;
paint.begin(&p2); // p2被修改
paint.drawText(0,50,"Hi");
paint.end(); // 这个例子采用了引用计数,不清楚的看看共享指针原理
深复制和浅复制。深复制意味着复制一个对象,而浅复制则是复制一个引用(仅仅只是一个指向共享数据块的指针)。深复制非常耗能,需要消耗很多内存和CPU资源;而浅复制则非常快速,因为它只需要设置一个指针和增加引用计数的值。当隐式共享类使用"=“操作符时就使用浅复制,如"p2 = p1”,但是当对象被修改时,才必须进行深复制(这也是指针灵活的地方)。
共享的好处是程序不需要进行不必要的数据复制,从而减少数据的复制和使用更少的内存,对象也可以很容易地被分配,或者作为参数被传递,或者从函数被返回。隐式共享在后台进行,实际编程不必关注。