C++ DAY7

一、类模板

建立一个通用的类,其类中的类型不确定,用一个虚拟类型替代

template<typename T>
类

template ----->表示开始创建模板
typename -->表明后面的符号是数据类型,typename 也可以用class代替
T  ----->表示数据类型,可以其他符号代替

使用类模板的时候,需要表明模板参数类型

#include <iostream>

using namespace std;

//声明创建类模板
template <typename T, typename N>
class A
{
private:
    T n;
    N b;
public:
    A(){}

    A(T n, N b):n(n),b(b){}

    void show()
    {
        cout << n << endl;
        cout << b << endl;
    }
};

int main()
{
    A<string,int> a("zhangsan",1001);//使用类模板的时候,需要表明模板参数类型
    a.show();

    A<int, char> b(34,'w');
    b.show();

    return 0;
}

二、异常

更优雅的解决代码中的问题和异常,可以发现异常并处理进行分开

#include <iostream>


using namespace std;


int fun(int a, int b)
{
    if(b!=0)
    {
        return a/b;
    }
    else
    {
        throw -1;
    }
}


int main()
{
    try{
        fun(9,0);  //把可能出现异常的代码用try包裹起来
        cout << "hello world" << endl;
    }catch(int e)
    {
        if(e == -1)
        {
            cout << "分母不能为0" << endl;
        }
    }
    return 0;
}

三、auto关键字

用来修饰变量,作为自动类型推导,推导出变量的数据类型

注意

1> 使用auto修饰变量时,必须初始化

2> auto的右值,可以是右值,也可以是表达式,还可以是函数的返回值

3> auto不能直接声明数组

4> auto不能作为函数的形参

5> auto不能修饰非静态成员

主要用于修饰冗长的数据类型,使用在函数模板中,依赖模板参数的变量。

四、lambda表达式

当你需要一个匿名的、临时的、需要获得外界变量的函数时,可以用lambda来完成。

#include <iostream>

int main() {
    int a = 1, b = 2;
    
    // 值捕获
    auto sum1 = [a, b]() { return a + b; };
    std::cout << "sum1: " << sum1() << std::endl;
    
    // 引用捕获,由于是引用,出了作用域也会修改a、b值
    auto sum2 = [&a, &b]() { return a + b; };
    std::cout << "sum2: " << sum2() << std::endl;
    
    // 混合捕获
    auto sum3 = [a, &b]() { return a + b; };
    std::cout << "sum3: " << sum3() << std::endl;
    
    // 值捕获,但使用mutable使其可修改 出了作用域后不修改值
    auto sum4 = [a, b]() mutable { a = a + 1; return a + b; };
    std::cout << "sum4: " << sum4() << std::endl;
    
    // 指定返回类型
    auto sum5 = [a, b]() -> int { return a + b; };
    std::cout << "sum5: " << sum5() << std::endl;
    
    return 0;
}

五、数据库类型转换

1>隐式类型转换(自动类型转换)

这是C++编译器自动执行的类型转换,通常在表达式中出现时发生。例如,将较小的整数转换为较大的整数类型,将整数提升为浮点数等。

2>显示类型转换(强制类型转换)

通过使用强制类型转换操作符来显示执行类型转换。这种转换可能会导致数据的截断或者精度丢失,因此要小心使用。

(1)静态转换(static_cast)

用于基本数据类型之间的转换

以及父类指针/引用转换为子类指针/引用

还可以用于不同类型的指针之间的转换

double num_double = 3.14;
int num_int = static_cast<int>(num_double);  // 显式将double转换为int

(2)动态转换(dynamic_cast)

通常用于多态类之间的指针或引用类型转换,确保类型安全。在运行时进行类型检查,只能用于具有虚函数的类之间的转换

class Base {
    virtual void foo() {}
};
class Derived : public Base {};

Base* base_ptr = new Derived;
Derived* derived_ptr = dynamic_cast<Derived*>(base_ptr);  // 显式将基类指针转换为派生类指针

(3)常量转换(const_cast)

用于添加或移除指针或引用的常量性。它可以用来去除const限定符,但要注意潜在的未定义行为

const int a =10; //
int *p;
p = &a; // 合不合法?   no
        //如果能这样使用,那就可以通过指针取值去改const修饰的值了,这就和const修饰相悖了
**************************************

const int num_const = 5;
int* num_ptr = const_cast<int*>(&num_const);  // 去除const限定符

(4)重新解释转换(reinterpret_cast)

执行低级别的位模式转换,通常用于指针之间的类型转换。它可能导致未定义行为,因此要谨慎使用

int num = 42;
float* float_ptr = reinterpret_cast<float*>(&num);  // 重新解释转换

3>c风格类型转换

可以使用C样式转换

int num_int = 10;
double num_double = (double)num_int;  // C样式强制类型转换

函数样式转换:C++中使用的类型转换

int num_int = 10;
double num_double = double(num_int);  // C++函数样式类型转换

在使用强转的时候要注意潜在问题和错误,保证操作是安全的。

关键字总结

 63个关键字,红色(不包括class,class是修改之前的错误)的32个是c中的关键字

1>
asm
1:这是一个用于嵌入汇编语言代码的关键字。它允许你在C++代码中直接插入汇编指令,通常用于执行特定的底层操作。然而,由于现代C++提供了更强大的抽象和跨平台性,通常不建议使用这个关键字。
explicit
2:这个关键字通常用于禁止隐式类型转换的发生。当一个构造函数被声明为explicit时,它将不会在隐式类型转换中被调用,只能在显式构造函数调用中使用。
export
3:在C++中,export关键字用于指示一个模板的定义将在另一个文件中实例化。然而,在实际的C++标准中,export关键字的语法并未最终确认,并且在许多编译器中也未被实现。在C++20中,export被重新引入,但是它的主要用途是与模块化编程相关,而不是之前模板实例化的用法。
goto
4:goto是一个跳转语句,允许你无条件地将程序的控制转移到指定的标签处。然而,由于使用goto会导致代码结构变得混乱和难以维护,现代编程实践通常建议避免使用它。
register
5:在早期的C语言标准中,register关键字用于建议编译器将变量存储在寄存器中,以便提高访问速度。然而,现代编译器已经能够智能地管理寄存器分配,所以使用register关键字通常不再有明显的性能提升,并且在C++17中已被弃用。
volatile
6:volatile关键字用于告诉编译器不要对标记为volatile的变量进行优化,因为这些变量的值可能会在未知的时间被外部因素改变,比如硬件中断或多线程环境中的共享变量。这可以防止编译器对这些变量的读取和写入操作进行优化,以确保程序的行为是可预测的。


2>    数据类型相关的关键字
bool、true、false:对于bool类型数据的相关处理,值为true和false
char、wchar_t:char是单字符数据,wchar_t多字符数据
int、short、float、double、long:整数和实数的数据类型
signed、unsigned:定义有符号和无符号数据的说明符
auto:在c语言中,是存储类型,但是在C++中,是类型自动推导,注意事项有两个:
i>    连续定义多个变量时,初始值必须是相同数据类型,否则报错
ii>    auto p=&m;  与auto* p = &m;规定是一样
explicit:防止数据隐式转换
typedef:类型重定义
sizeof:求数据类型的字节运算


3>    语句相关的关键字
switch、case、default:实现多分支选择结构
do、while、for:循环相关的关键字
break、continue、goto:跳转语句
if、else:选择结构
inline:内联函数
return:函数返回值


4>    存储类型相关的关键字
static、const、volatile、register、extern、auto


5>    构造数据类型相关
struct、union:结构体和共用体
enum:枚举
class:类


6>    访问权限:public、protected、private


7>    异常处理:throw、try、catch


8>    类中相关使用关键字
this:指代自己的指针
friend:友元
virtual:虚
delete、default:对类的特殊成员函数的相关使用
例如:Test(const Test &) = default;    ~Test()  = delete;
mutable:取消常属性
using:引入数据,有三种使用方式
i>    使用命名空间的关键字
ii> 相当于类型重定义
iii> 修改子类中从父类继承下来成员的权限
operator:运算符重载关键字


9>    类型转换相关的关键字
static_cast、dynamic_cast、const_cast、reinterpret_cast


10>    模板相关的关键字:template、typename


11>    命名空间相关:using、namespace


12>    export:导入相关模板类使用


13>    内存分配和回收:new、delete

六、C++标准模板库(STL)

标准模板库中使用了大量的函数模板和类模板,来对数据结构和算法的处理。

STL主要由 容器、算法、迭代器组成。

容器:置物之所也

数组、链表、队列、栈、集合。。。

算法:问题之解法也

增、删、改、查

迭代器:是容器和算法之间的粘合剂 (== 指针)

6.1vector

类似于数组、也可称之为单端数组

和普通数组的区别:普通数组是静态空间,vector是动态拓展。

动态拓展:不是在原来空间后续接空间,而是重新申请更大的空间,将原来的数据拷贝到新的空间中。

vector的构造函数

        vector v;//无参构造

        vector(v.begin(),v.end()); //将区间[begin(),end()),拷贝给本身

        vector(const vector& v); //将v拷贝给本身

        vector(n, elem) ; //将n个elem拷贝给本身

#include <iostream>
#include <vector>

using namespace std;

//算法
void printVector(vector<int> &v)
{
    vector<int>::iterator iter; //定义了这样容器类型的迭代器
    for(iter = v.begin(); iter != v.end(); iter++)
    {
        cout << *iter << " ";
    }
    cout << endl;
}

int main()
{
    //容器
    vector<int> v; //无参构造函数
    v.push_back(10); //尾插
    v.push_back(20);
    v.push_back(30);
    v.push_back(40);

    //算法
    printVector(v);

    vector<int> v2(v.begin(),v.end());
    printVector(v2);

    vector<int> v3(6,100);
    printVector(v3);

    vector<int> v4 = v3;
    printVector(v4);


    vector<int> v5(v2);
    printVector(v5);

    return 0;
}

vector的赋值函数

        vector &operator = (const vector &v);//将v赋值给本身

        assign(beg,end); //将区间[begin(),end())赋值给本身

        assign(n, elem); //将n个elem赋值给本

vector容量大小

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

        capacity() ; //计算容器的容量大小

        size(); //计算容器大小 ---- 容器的元素个数

        resize(); //重新设置大小

vector的插入和删除 

        push_back(); //尾插

        pop_back(); //尾删

        insert(iterator pos,elem) //在迭代器指向的位置,插入数据

        insert(iterator pos,n, elem) //在迭代器指向的位置,插入n个数据

        erase(iterator pos); //删除迭代器指向元素

        erase(iterator start, iterator end); //删除区间的元素

        clear() ; //删除容器中所有的元素

vector的元素提取

        at(int idx);

        operator[](int idx);

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

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

七、文件操作

        由于程序运行时的数据都是历史数据,程序一旦结束,数据就会消失

头文件: #include<fstream>

文件操作的三大类

读文件:ifstream

写文件:ofstream

读写:fstream

7.1写入数据

1.包含头文件

#include

2.创建流对象

ofstream ofs;

3.打开文件

ofs.open("文件名",打开方式);

4.写入数据

ofs

5.关闭文件

ofs.close();

7.2读文件

1.包含头文件

#include

2.创建流对象

ifstream ifs;

3.打开文件

ifs.open("文件名",打开方式);

 

试编程:

封装一个学生的类,定义一个学生这样类的vector容器, 里面存放学生对象(至少3个)

再把该容器中的对象,保存到文件中。

再把这些学生从文件中读取出来,放入另一个容器中并且遍历输出该容器里的学生。

#include <iostream>
#include <vector>
#include <fstream>
#include <string>
using namespace std;

class Stu {
private:
    int classnum;
    int grade;
    string name;
public:
    Stu() {}
    Stu(int class_num, int grade, string name) : classnum(class_num), grade(grade), name(name) {}
    void set(int i, int g) {
        classnum = i;
        grade = g;
    }
    void name_set(string n) { name = n; }
    friend void ofs(vector<Stu>& p);
};

void ofs(vector<Stu>& p) {
    ofstream ofs;
    ofs.open("F:/test.txt", ios::out);
    for (const auto& student : p) {
        ofs << student.classnum << ' ' << student.grade << ' ' << student.name << endl;
    }
    ofs.close();
}

int main() {
    vector<Stu> p;
    for (int i = 0, j = 1; i < 2; i++, j++) {
        Stu student;
        student.set(i, j);
        if (0 == i) {
            student.name_set("lisi");
        } else if (1 == i) {
            student.name_set("zhangsan");
        }
        p.push_back(student);
    }

    ofs(p);

    return 0;
}

list相关函数

#include <iostream>
#include <list>

int main() {
  // 默认构造函数
  std::list<int> lst1;

  // 初始化列表构造函数
  std::list<int> lst2 = {1, 2, 3};

  // 拷贝构造函数
  std::list<int> lst3(lst2);

  // 填充构造函数
  std::list<int> lst4(3, 10);  // 3个元素,每个元素都是10

  // 赋值操作
  lst1 = lst2;

  // assign函数
  lst1.assign({4, 5, 6});
  lst2.assign(3, 7);  // 3个元素,每个元素都是7

  // 输出lst1
  for (std::list<int>::iterator it = lst1.begin(); it != lst1.end(); ++it) {
      int x = *it;
      std::cout << x << ' ';
  }
    std::cout<<std::endl;
  // 输出lst2
  for (std::list<int>::iterator it = lst2.begin(); it != lst2.end(); ++it) {
      int x = *it;
      std::cout << x << ' ';
  }

  return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值