首页 > 编程语言 >C++基础 抽象类 类模板 STL库 QT环境

C++基础 抽象类 类模板 STL库 QT环境

时间:2024-11-12 19:49:40浏览次数:3  
标签:容器 QT STL list pos C++ elem push

一、抽象类

1、纯虚函数

        在多态中,通常父类中虚函数的实现是毫无意义的,主要都是调用子类重写的内容,因此可以将虚函数改为纯虚函数。

        语法:

virtual 返回值类型 函数名 (参数列表) = 0;

2. 抽象类

1) 概念

        有纯虚函数所在的类,称为抽象类。

2) 特点

        抽象类不能直接定义对象。

        抽象类派生子类,子类必须实现所有的纯虚函数,否则子类也是一个抽象类。

        抽象类可以定义指针。


示例代码:

#include <iostream>
#define PI 3.14159
using namespace std;

class Shap{ // 抽象类
public:
    virtual double cal_s() = 0; // 纯虚函数
    virtual double cal_c() = 0;
    virtual void display() = 0;
};

class Square : public Shap{
private:
    int longa;
    int shorta;
public:
    Square(int a,int b):longa(a),shorta(b){};
    void display(){
        cout<<"Square:";
    }
    double cal_s(){
        return longa * shorta ;
    }
    double cal_c(){
        return 2 * (longa + shorta);
    }
};
class Circle : public Shap{
private:
    int r;
public:
    Circle(int r):r(r){};
    void display(){
        cout<<"Circle:";
    }
    double cal_s(){
        return PI * r * r;
    }
    double cal_c(){
        return 2 * PI * r ;
    }
};
class Single : public Shap{
private:
    int a;
    int b;
    int c;
public:
    Single(int a,int b,int c):a(a),b(b),c(c){};
    void display(){
        cout<<"Single:";
    }
    double cal_s(){
        return(b * a * c) ;
    }
    double cal_c(){
        return a + b+  c;
    }
};
void cal_s(Shap *p){
    p->display();
    cout<<"S = "<<p->cal_s()<<endl;
}
void cal_c(Shap *p){
    p->display();
    cout<<"C = "<<p->cal_c()<<endl;
}

int main(){
    Square a(2,3);
    Single b(1,3,3);
    Circle c(3);
    cal_c(&a);
    cal_s(&a);
    cal_c(&b);
    cal_s(&b);
    cal_c(&c);
    cal_s(&c);
    return 0;
}

输出:


二、类模板

1. 概念

        实现一个通用类,类中所需的类型使用虚拟类型表示。一般通过类模板实现不同的数据结构,实现数据类型与数据结构的分离。同一个数据结构可以存储不同类型的数据。

2. 语法

Template <class/typename T>

Class  类名{ ...  ...  };

3. 使用类模板定义对象

        必须显示指定类型。

        类名 <指定类型>  对象名;

        C++编译器会根据指定类型将类模板生成具体的类,然后再使用。

4. 类模板中的继承

        派生普通类,必须指定具体类型派生

 Class 派生类名: public 类模板<指定类型> {  ... ...  };

5. 类模板中的static成员

        从类模板实例化的每个模板类都有自己的静态成员,同一个模板类的对象共享一个静态成员。


三、STL库

1. 理论

        STL(Standard Template Library,标准模板库)是惠普实验室开发的一系列软件的统称。现然主要出现在C++中,但在被引入C++之前该技术就已经存在了很长的一段时间。

        STL的从广义上讲分为三类:algorithm(算法)、container(容器)和iterator(迭代器),容器和算法通过迭代器可以进行无缝地连接。几乎所有的代码都采 用了模板类和模板函数的方式,这相比于传统的由函数和类组成的库来说提供了更好的代码重用机会。

        在C++标准中,STL被组织为下面的13个头文 件:<algorithm>、<deque>、<functional>、<iterator>、<vector>、<list>、<map>、<memory>、<numeric>、<queue>、<set>、<stack> <utility>

Class 派生类名: public 类模板<指定类型> {  ... ...  };

STL详细的说六大组件

  • 容器(Container)
  • 算法(Algorithm)
  • 迭代器(Iterator)
  • 仿函数(Function object)
  • 适配器(Adaptor)
  • 空间配制器(allocator)

使用STL的好处

(1)STL是C++的一部分,因此不用额外安装什么,它被内建在你的编译器之内。

(2)STL的一个重要特点是数据结构和算法的分离。尽管这是个简单的概念,但是这种分离确实使得STL变得非常通用。例如,在STL的vector容器中,可以放入元素、基础数据类型变量、元素的地址;STL的sort()函数可以用来操作vector,list等容器。

        1) 程序员可以不用思考STL具体的实现过程,只要能够熟练使用STL就OK了。这样他们就可以把精力放在程序开发的别的方面。

        2) STL具有高可重用性,高性能,高移植性,跨平台的优点。

        高可重用性:STL中几乎所有的代码都采用了模板类和模版函数的方式实现,这相比于传统的由函数和类组成的库来说提供了更好的代码重用机会。关于模板的知识,已经给大家介绍了。

        高性能:如map可以高效地从十万条记录里面查找出指定的记录,因为map是采用红黑树的变体实现的。(红黑树是平横二叉树的一种)

        高移植性:如在项目A上用STL编写的模块,可以直接移植到项目B上。

        跨平台:如用windows的Visual Studio编写的代码可以在Mac OS的XCode上直接编译。

        1) 程序员可以不用思考STL具体的实现过程,只要能够熟练使用STL就OK了。这样他们就可以把精力放在程序开发的别的方面。

        2) 了解到STL的这些好处,我们知道STL无疑是最值得C++程序员骄傲的一部分。每一个C++程序员都应该好好学习STL。只有能够熟练使用STL的程序员,才是好的C++程序员。

        3) 总之:招聘工作中,经常遇到C++程序员对STL不是非常了解。大多是有一个大致的映像,而对于在什么情况下应该使用哪个容器和算法都感到比较茫然。STLC++程序员的一项不可或缺的基本技能,掌握它对提升C++编程大有裨益。


2. 容器

        (1) 作用:    

        用来管理一组数据

        (2) 分类:
        1) 序列式容器(Sequence containers)

        序列式容器是一种数据结构,它以线性序列的方式来存储某一特定类型的数据。这类容器并不会自动对存储的元素按照值的大小进行排序,而是保持元素的存储顺序与其在容器中的顺序一致。

        2) 关联式容器(Associated containers)

        关联式容器是一种数据结构,它支持高效的关键字查找和访问。关联式容器依照特定的排序准则自动为元素排序。


3. Vector

1) vector容器简介

        vector是将元素置于一个动态数组中加以管理的容器,是通过类模板实现。

        vector可以随机存取元素(支持索引值直接存取, 用[]操作符或at()方法)。

        vector尾部添加或移除元素非常快速。但是在中部或头部插入元素或移除元素比较费时

        包含头文件: #include <vector>

2) vector与普通数组的区别

        普通数组是静态空间,vector可以动态拓展。

        动态拓展:并不是在原空间之后接新的空间,而是找更大的内存空间,然后将

原数据拷贝到新空间,释放原空间。

3) 创建对象

        vector<T> vecT;  // 采用类模板实现,默认构造函数

        vector(beg,end);  // 构造函数将[beg, end)区间中的元素拷贝给本身。注意该区间是左闭右开的区间。

        vector(n,elem);   // 构造函数将n个elem拷贝给本身。

        vector(const vector &vec);  // 拷贝构造函数

4) 插入数据

        insert(pos,elem); //在pos位置插入一个elem元素的拷贝

        insert(pos,n,elem);   //在pos位置插入n个elem数据,无返回值。

        insert(pos,beg,end);   //在pos位置插入[beg,end)区间的数据,无返回值

5) 遍历

        at(int  index);//返回下标index所在的元素

        operator[];//返回下标index所在的元素

        迭代器的方式遍历;//迭代器支持随机操作

6) 属性操作

        size(); //获取容器大小

        resize(); //设置容器大小

        empty();//判断容器是否为空

7) 数据的存取

        back(); // 返回最后一个元素

        front(); // 返回第一个元素

        push_back(); // 尾部追加

        pop_back(); // 尾部删除

8) 删除操作

        clear();     //移除容器的所有数据

        erase(beg,end);  //删除[beg,end)区间的数据,返回下一个数据的位置

        erase(pos);    //删除pos位置的数据,返回下一个数据的位置


示例代码:

#include <iostream>
#include <vector>
using namespace std;
 
int main(){
    vector<int> v;
    vector<int>::iterator it;
    v.push_back(1); // 尾端插入元素
    v.push_back(2);
    v.push_back(3);
    v.push_back(4);
    v.push_back(5);
 
    // 插入
    it =  v.begin();
    v.insert(it + 2,9);
 
    // 遍历
    for(int i = 0;i<v.size();i++)
        cout<<v[i]<<" ";
    cout<<endl;
 
    // 删除最后一个元素
    v.pop_back();
 
    // at遍历
    for(int i = 0;i<v.size();i++)
        cout<<v.at(i)<<" ";
    cout<<endl;
 
    // 删除(左闭右开)
    v.erase(it,it + 2);
 
    // 迭代器遍历
    for(vector<int>::iterator it =  v.begin();it != v.end();it++)
        cout<<*it<<" ";
    cout<<endl;
 
    // 删除
    it = v.begin();
    v.erase(it + 1);
 
    // 迭代器逆向遍历
    cout<<"迭代器逆向遍历"<<endl;
    for(vector<int>::reverse_iterator it =  v.rbegin();it != v.rend();it++)
        cout<<*it<<" ";
    cout<<endl;
 
    // 清空
    v.clear();
 
    if(v.empty()) cout<<"is empty"<<endl;
    else cout<<"is not empty"<<endl;
 
    return 0;
}

输出:


4. Deque

1) deque简介

        deque是双端数组,也是通过类模板实现,deque头部和尾部添加或移除元素都非常快速。但是在中部安插元素或移除元素比较费时。

        包含头文件:#include <deque>

2) 创建对象

        deque<T> deqT;

        deque(beg,end);    //构造函数将[beg, end)区间中的元素拷贝给本身。注意该区间是左闭右开的区间。

        deque(n,elem);   //构造函数将n个elem拷贝给本身。

        deque(const deque  &deq);  //拷贝构造函数。

3) 插入数据

        deque.insert(pos,elem);   // 在pos位置插入一个elem元素的拷贝,返回新数据的位置。

        deque.insert(pos,n,elem);   // 在pos位置插入n个elem数据,无返回值。

        deque.insert(pos,beg,end);   // 在pos位置插入[beg,end)区间的数据,无返回值。

4) 遍历

        at(int  index); //返回下标index所在的元素

        operator[]; //返回下标index所在的元素

        迭代器的方式遍历;//迭代器支持随机操作

5) 属性操作

        size(); //获取容器大小

        resize(); //设置容器大小

        empty(); //判断容器是否为空

6) 数据的存取

        back(); //返回最后一个元素

        front(); //返回第一个元素

        push_back(); //尾部追加

        pop_back(); //尾部删除

        push_front(); //头部插入

        pop_front(); //头部删除

7) 删除

        clear();     //移除容器的所有数据

        erase(beg,end);  //删除[beg,end)区间的数据,返回下一个数据的位置

        erase(pos);    //删除pos位置的数据,返回下一个数据的位置

示例代码:

#include <iostream>
#include <deque>
 
using namespace std;
 
// 输出
void display(deque<int> d){
    deque<int>::iterator it;
    cout<<"deque :";
    for(it = d.begin();it != d.end();it++)
        cout<<*it<<" ";
    cout<<endl;
}
 
int main(){
    deque<int>d;
    deque<int>::iterator it;
    
    d.push_back(1); // 尾部追加
    d.push_back(2);
    d.push_back(3);
    d.push_front(-1); // 头部追加
    d.push_front(-2);
    d.push_front(-3);
    display(d);
    cout<<"第一个元素:"<<d.front()<<endl;
    cout<<"最后一个元素:"<<d.back()<<endl;
 
    cout<<"删除尾端元素"<<endl;
    d.pop_back(); // 删除尾端元素
 
    display(d);
    cout<<"删除头端元素"<<endl;
    d.pop_front(); // 删除头端元素
 
    display(d);
    cout<<"在第2个位置插入3个9"<<endl;
    it = d.begin();
    d.insert(it + 1,3,9); // 插入
 
    display(d);
    return 0;
}

输出:


5. List

1) list简介

        list是一个双向链表容器,可高效地进行插入删除元素,通过类模板实现。

        list不可以随机存取元素,所以不支持 at.(pos) 函数与[]操作符。it++(ok) it+5(err)

        包含头文件:#include <list>

2) 创建对象

        list<T> lstT; // 默认构造函数

        list(beg,end); // 构造函数将[beg, end)区间中的元素拷贝给本身。注意该区间是左闭右开的区间

        list(n,elem);   // 构造函数将n个elem拷贝给本身

        list(const list &lst);  // 拷贝构造函数

3) 插入数据

        list.insert(pos,elem);   // 在pos位置插入一个elem元素的拷贝

        list.insert(pos,n,elem);   // 在pos位置插入n个elem数据,无返回值

        list.insert(pos,beg,end);   // 在pos位置插入[beg,end)区间的数据,无返回值

4) 遍历

        通过迭代器遍历。迭代器只能进行自增操作,不支持it+n的操作。

5) 属性操作

     size(); // 获取容器大小

     resize(); // 设置容器大小

     empty(); // 判断容器是否为空

6) 数据的存取

      back(); // 获取尾部元素

      front(); // 获取头部元素

      push_back(); // 尾部追加

      push_front(); // 头部追加

      pop_back(); // 尾部删除

      pop_front(); // 头部删除

7) 删除

        list.clear();        //移除容器的所有数据

        list.erase(beg,end);  //删除[beg,end)区间的数据,返回下一个数据的位置

        list.erase(pos);    //删除pos位置的数据,返回下一个数据的位置

        list.remove(elem);   //删除容器中所有与elem值匹配的元素

8) 排序

        List.sort() ;   //默认按照升序排序

        List.sort(com); // 将比较规则的入口地址传过来,可以实现升序或者降序,也可以对自定义的数据类型进行排序

示例代码:

#include <iostream>
#include <list>
using namespace std;

// 输出
void display(list<int> l){
    list<int>::iterator it;
    cout<<"list :";
    for(it = l.begin();it != l.end();it++)
        cout<<*it<<" ";
    cout<<endl;
}

// 比较规则
bool Compare(int &x,int &y){
    return x > y ? true : false;
}

int main(){
    list<int> l;
    list<int>::iterator it;
    l.push_back(1);
    l.push_back(3);
    l.push_back(2);
    l.push_front(-2);
    l.push_front(-1);
    l.push_front(-3);
    display(l);
    cout<<"第一个元素: "<<l.front()<<endl;
    cout<<"最后一个元素: "<<l.back()<<endl;

    cout<<"删除尾端元素"<<endl;
    l.pop_back(); // 删除尾端元素
    display(l);

    cout<<"删除头端元素"<<endl;
    l.pop_front(); // 删除头端元素
    display(l);

    cout<<"在第2个位置插入2个9"<<endl;
    it = l.begin();
    it++;
    l.insert(it,2,9); // 插入元素
    // it执行完上述代码后指向第4个元素
    display(l);

    cout<<"删除第3个元素"<<endl;
    l.erase(--it); // 删除第3个元素
    display(l);
    cout<<"默认升序排序"<<endl;
    l.sort();
    display(l);
    cout<<"降序排序"<<endl;
    //l.sort(Compare); // 通过函数指针传入比较规则
    l.sort();l.reverse(); // 先升序排序,然后再翻转
    display(l);
    return 0;
}

输出:

标签:容器,QT,STL,list,pos,C++,elem,push
From: https://blog.csdn.net/2301_77329667/article/details/143721992

相关文章

  • C++中的命名空间
    C++命名空间:命名空间是一个声明性区域,为其内部的标识符(类型、函数和变量等的名称)提供一个范围。命名空间用于将代码组织到逻辑组中,还可用于避免名称冲突,尤其是在基本代码包括多个库时。命名空间范围内的所有标识符彼此可见,而没有任何限制。命名空间之外的标识符可通过使用......
  • 【c++】vector
    序列式容器vectorstd::vector 是STL提供的 内存连续的、可变长度 的数组(亦称列表)数据结构。能够提供线性复杂度的插入和删除,以及常数复杂度的随机访问。为什么要使用 vector作为OIer,对程序效率的追求远比对工程级别的稳定性要高得多,而 vector 由于其对内存的动态......
  • 【c++】运算详解
    运算算术运算符运算符功能+ (单目)正- (单目)负* (双目)乘法/除法%取模+ (双目)加法- (双目)减法单目与双目运算符单目运算符(又称一元运算符)指被操作对象只有一个的运算符,而双目运算符(又称二元运算符)的被操作对象有两个。例如 1+2 中加号就是双目运算符,它有 1 和 2 两......
  • 【c++】枚举详解
    简介枚举(英语:Enumerate)是基于已有知识来猜测答案的一种问题求解策略。枚举的思想是不断地猜测,从可能的集合中一一尝试,然后再判断题目的条件是否成立。要点给出解空间建立简洁的数学模型。枚举的时候要想清楚:可能的情况是什么?要枚举哪些要素?减少枚举的空间枚举的范围是......
  • 【c++】结构体和类详解
    结构体结构体(struct),可以看做是一系列称为成员元素的组合体。可以看做是自定义的数据类型。Note本页描述的 struct 不同于C中 struct,在C++中 struct 被扩展为类似 class 的类说明符。定义结构体structObject{intweight;intvalue;}e[array_length];......
  • 常用的物联网消息队列-Mqtt协议
    EMQX和Mosquitto都是广泛使用的MQTT消息代理,但它们在设计目标、功能和适用场景上有一些显著的区别。Emqx使用教程添加依赖<dependency><groupId>org.eclipse.paho</groupId><artifactId>org.eclipse.paho.client.mqttv3</artifactId><version>1.2.5</......
  • C++笔记---智能指针
    1.什么是智能指针1.1 RALL设计思想RAII(ResourceAcquisitionIsInitialization,资源获取即初始化)是一种资源管理类的设计思想,广泛应用于C++等支持对象导向编程的语言中。它的核心思想是将资源的管理与对象的生命周期紧密绑定,通过在对象的构造函数中获取资源,并在析构函数中......
  • 打卡信奥刷题(222)用C++信奥P1746[普及组/提高] 离开中山路
    离开中山路题目背景《爱与愁的故事第三弹·shopping》最终章。题目描述爱与愁大神买完东西后,打算坐车离开中山路。现在爱与愁大神在x1,......
  • Qt滑动条美化自定义
    效果展示主要代码头文件下面是hi控件的头文件,我们继承一个Qt原生的滑动条类QSlider,然后在基类的基础上进行自定义,我会对重要的变量进行解析:classXSlider:publicQSlider{Q_OBJECTpublic:explicitXSlider(QWidget*parent=nullptr);protected:......
  • C++语法·三
    内联函数(inline)简介:用inline修饰的函数叫内联函数,编译时C++编译器会在调用的地方站开内联函数,这样调用函数就不需要创建栈帧了,可以提高效率。内联函数与宏函数:C++中的内联函数与C中的宏函数很相似,都是直接在预处理时展开函数,将函数直接替换到调用位置,不额外创建栈帧。但内联......