【黑马程序员】C++模版

20240214

文章目录

  • C++泛型编程技术
    • 模版的概念
  • 函数模版
    • 函数模版语法
    • 不使用模版的模版完成两个数交换
    • 使用模版的方式完成两个数的交换
    • 模版注意事项
    • 函数模版案列
      • 使用模版实现升序选择排序
    • 模版函数和普通函数
      • 区别点
      • 调用规则
    • 模版的局限性
      • 模版的通用性问题
      • 模版重载
  • 类模板
    • 类模板语法
    • 类模板和函数模版区别
    • 类模板中成员函数创建时机
    • 类模板对象做函数参数
      • 指定传入类型
      • 参数模板化
      • 类模版化
    • 类模版和继承
    • 类模板成员函数类外实现
    • 类模板分文件编写
      • 问题
      • 解决方法
    • 类模板与友元
  • 类模板案例
    • 实现一个通用数组类
      • 功能需求
    • 功能实现
    • 功能测试

C++泛型编程技术

模版的概念

  • 模版就是建立通用的模具,大大提高通用性
  • C++除了面向对象的编程思想之外,还有另一种编程思想泛型编程,主要利用的技术就是模版
  • c++提供两种模版模版机制:函数模版和类模板

函数模版

函数模版语法

  • 函数模版作用:建立一个通用函数,其函数返回值和参数类型不具体指定,用一个虚拟的类型来表示
  • 语法:
template <typename T>
函数声明或定义
  • 说明:

    • template:声明创建模版
    • typename:表名其后面的符号是一种数据类型,可以用class代替
    • T:通用数据类型,名称可以替换,通常为大写英文字母
  • 函数模版使用方式

    • 自动类型推导:swap(a, b)
    • 显示指定类型:swap<int>(a, b)

不使用模版的模版完成两个数交换

  • 假设现在有交换整数和交换浮点数的需求
  • 后面可能还会有交换其他类型数的需求
  • 这样每多增一种类型比较就需要重载一份类型不同的交换函数
  • 代码示例
#include <iostream>using namespace std;// 交换两个整形数
void swapNum(int &a, int &b) {int tmp = a;a = b;b = tmp;
}// 交换两个浮点型数
void swapNum(float &a, float &b) {float tmp = a;a = b;b = tmp;
}void test() {int a = 10, b = 20;cout << "整形交换前 a: " << a << " b: " << b << endl;swapNum(a, b);cout << "整形交换后 a: " << a << " b: " << b << endl;float c = 3.14, d = 5.21;cout << "整形交换前 c: " << c << " d: " << d << endl;swapNum(c, d);cout << "整形交换后 c: " << c << " d: " << d << endl;
}int main() {test();return 0;
}

使用模版的方式完成两个数的交换

  • 根据上面不使用模版的方式,交换两个数时只是进行函数重载,变更交换的数据类型
  • 这种情况恰好使用泛型编程的思想,参数类型不定其它都确定
  • 代码示例
#include <iostream>using namespace std;template<typename T>
void swapNum(T &a, T &b) {T tmp = a;a = b;b = tmp;
}void test() {int a = 10, b = 20;cout << "整形交换前 a: " << a << " b: " << b << endl;// 自动类型推导swapNum(a, b);cout << "整形交换后 a: " << a << " b: " << b << endl;float c = 3.14, d = 5.21;cout << "整形交换前 c: " << c << " d: " << d << endl;// 显示指定类型    swapNum<float>(c, d);cout << "整形交换后 c: " << c << " d: " << d << endl;
}int main() {test();return 0;
} 
  • 结果示例

在这里插入图片描述

模版注意事项

  • 使用自动推导的方式时,推导出来的数据类型必须一致才可以使用
template<typename T>
void swapNum(T &a, T &b) {T tmp = a;a = b;b = tmp;
}void test1() {int a = 10;char b = 20;// error: no matching function for call to 'swapNum'// candidate template ignored: deduced conflicting types for parameter 'T' ('int' vs. 'char')    // swapNum(a, b);
} 
  • 模版必须要确定出数据类型T才可以使用
#include <iostream>using namespace std;template<class T>
void func() {cout << "func()" << endl;
}// 模版必须要确定出类型T才可以使用
void test1() {// error: no matching function for call to 'func'// func();func<int>();
}int main() {test1();return 0;
} 

函数模版案列

使用模版实现升序选择排序

  • 需求分析
    • 首先要实现主要的升序排序函数
    • 在排序中需要实现交换函数
    • 在排序前后要实现不同类型的数组打印
  • 代码示例
#include <iostream>using namespace std;// 定义模版交换
template<class T>
void swapNum(T &a, T &b) {T tmp = a;a = b;b = tmp;
}// 定义打印模版
template<class T>
void printArr(const T &arr) {for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) {cout << arr[i] << " ";}cout << endl;
}// 定义模版选择排序
template<class T>
void selectAscSort(T *arr, int count) {for (int i = 0; i < count; i++) {for (int j = 0; j < count - i - 1; j++) {if (arr[j] > arr[j + 1]) {swapNum(arr[j], arr[j + 1]);}}}
}// 测试整形数组排序
void testInt() {int arr[5] = {3, 6, 1, 5, 9};cout << "整型数组排序前:";printArr(arr);selectAscSort<int>(arr, sizeof(arr) / sizeof(arr[0]));cout << "整型数组排序后:";printArr(arr);
}// 测试浮点型数组排序
void testDouble() {double arr[10] = {3.12, 4.32, 1.65, 5.6, 7.91, 5.05, 0.19, 4.32, 8.22, 3.97};cout << "浮点型数组排序前:";printArr(arr);selectAscSort<double>(arr, sizeof(arr) / sizeof(arr[0]));cout << "浮点型数组排序后:";printArr(arr);
}int main() {testInt();testDouble();return 0;
} 
  • 结果示例

在这里插入图片描述

模版函数和普通函数

区别点

  • 普通函数调用时,可以发生自动类型转换(隐式类型转换)
#include <iostream>using namespace std;// 普通函数
int myAdd(int a, int b) {return a + b;
}// 普通函数类型自动类型转换测试
void test1() {int a = 10;int b = 10;char c = 'a';cout << "调用普通函数不发生隐式类型转换:" << myAdd(a, b) << endl;cout << "调用普通函数发生隐式类型转换:" << myAdd(a, c) << endl;
}int main() {test1();return 0;
}
  • 模版函数调用时,如果利用自动类型推导,不会发生自动类型转换
  • 如果利用显示指定类型方式时,可以发生自动类型转换
#include <iostream>using namespace std;// 定义模版加法函数
template<typename T>
T myAdd(T a, T b) {return a + b;
}void test() {int a = 1;char b = 'a';// 调用时使用自动类型推导不发生隐式类型转换// candidate template ignored: deduced conflicting types for parameter 'T' ('int' vs. 'char')// cout << "自动类型推导时不发生隐式类型转换:" << myAdd(a, b) << endl;// 显示指定类型调用时,发生自动类型转换cout << "显示指定类型调用时,发生自动类型转换:" << myAdd<int>(a, b) << endl;
}int main() {test();return 0;
} 

调用规则

  • 如果普通函数和模版函数都可以实现,优先调用普通函数
  • 可以通过空模版参数列表来强制调用函数模版
  • 函数模版也可以发生重载
  • 如果函数模版可以产生更好的匹配,优先使用函数模版
  • 代码示例
#include <iostream>using namespace std;// 普通函数
int add(int a, int b) {cout << "int add(int a, int b)" << endl;return a + b;
}// 模版函数
template<typename T>
T add(T a, T b) {cout << "T add(T a, T b)" << endl;return a + b;
}// 模版函数
template<typename T>
T add(T a, T b, T c) {cout << "T add(T a, T b, T c)" << endl;return a + b + c;
}void test() {int a = 10;int b = 20;int c = 20;// 如果普通函数和模版函数都可以实现,优先调用普通函数add(a, b);// 可以通过空模版参数列表来强制调用函数模版add<>(a, b);// 函数模版也可以发生重载add(a, b, c);// 如果函数模版可以产生更好的匹配,优先使用函数模版char c1 = 'a', c2 = 'b';// char可以隐式类型转换成int,也可以直接调用add(char, char),显然模版的匹配更好add(c1, c2);
}int main() {test();return 0;
} 

模版的局限性

模版的通用性问题

  • 例如给类型直接传数组或者自定类型,在类似赋值之类的操作中就不能直接使用
#include <iostream>using namespace std;template<class T>
void func(T a, T b) {if (a == b) {cout << "a == b" << endl;} else {{cout << "a != b" << endl;}}return;
}// 普通类型直接比没问题
void test1() {int a = 1;int b = 2;func(a, b);
}void test2() {int a[3] = {1, 2, 3};int b[3] = {1, 2, 3};// a != b    func(a, b);
}struct A {int a;
};void test3() {A a1;A a2;// error: invalid operands to binary expression ('A' and 'A')// func(a1, a2);
}int main() {test1();test2();test3();return 0;
}

模版重载

  • C++为了解决模版通用性的局限问题,可以为这些特殊的类型提供具体化的模版
  • 使用具体化模版比较自定义数据类型
#include <iostream>using namespace std;template<class T>
void func(T a, T b) {if (a == b) {cout << "a == b" << endl;} else {{cout << "a != b" << endl;}}return;
}struct A {int a;
};// 实现A结构具体化的比较操作
template<>
void func(struct A a, struct A b) {if (a.a == b.a) {cout << "a.a == b.a" << endl;} else {{cout << "a.a != b.a" << endl;}}return;
}void test() {struct A a1;struct A a2;a1.a = 1;a2.a = 2;// error: invalid operands to binary expression ('A' and 'A')func(a1, a2);
}int main() {test();return 0;
} 

类模板

类模板语法

  • 类模板作用:建立一个通用类,类中的成员数据类型可以不具体指定,用一个虚拟的类型来表示
  • 语法:
template <class T>
  • 类模板代码示例
#include <iostream>using namespace std;template<class NameType, class AgeType>
class Person {
public:Person(NameType name, AgeType age) {this->name = name;this->age = age;}NameType name;AgeType age;
};void test() {Person<string, int> p("zsx", 18);cout << p.name << "     " << p.age << endl;
}int main() {test();return 0;
}

类模板和函数模版区别

  • 类模板没有自动类型推导的使用方式
  • 类模板在模版参数中可以有默认参数
  • 代码示例
#include <iostream>using namespace std;//AgeType=int 给定 AgeType 的默认参数为int
template<class NameType, class AgeType=int>
class Person {
public:Person(NameType name, AgeType age) {this->name = name;this->age = age;}NameType name;AgeType age;
};void test() {// 不能进行自动类型推导// too few template arguments for class template 'Person'// Person<> p("zsx", 18);// 缺省使用AgeType的默认参数列表类型intPerson<string> p("zsx", 18);cout << p.name << "     " << p.age << endl;
}int main() {test();return 0;
} 

类模板中成员函数创建时机

  • 类模板中的成员函数并不是在一开始创建的,而是在模版调用时在生成
  • 代码示例
#include <iostream>using namespace std;class P1 {
public:void showPInfo1() {cout << "P1 showPInfo()" << endl;}
};class P2 {
public:void showPInfo2() {cout << "P2 showPInfo()" << endl;}
};template<class T>
class myClass {
public:// 类模板中的成员函数并不是在一开始创建的,而是在模版调用时在生成void func1() {obj.showPInfo1();}void func2() {obj.showPInfo2();}T obj;
};void test() {myClass<P1> p1;p1.func1();// showPInfo2 不是P1中的对象// error: no member named 'showPInfo2' in 'P1'// p1.func2();
}int main() {test();return 0;
} 

类模板对象做函数参数

  • 类模板实例化出对象,向函数传参的方式
  • 创建类模版代码示例
  • 通过类模板创建对象,向函数中进行传参的方式
    • 指定出入类型(最常用的方式)
    • 参数模版化
    • 类模版化
#include <iostream>using namespace std;template<class T1, class T2>
class Person {
public:Person(T1 name, T2 age) {this->name = name;this->age = age;}void showPerson() {cout << "姓名:" << name << " 年龄:" << age << endl;}T1 name;T2 age;
}; 

指定传入类型

  • 直接显示对象的数据类型
  • 代码示例
// 指定传入类型
void printPerson1(Person<string, int> &p) {p.showPerson();
}void test1() {Person<string, int> p("zs", 12);printPerson1(p);
} 

参数模板化

  • 将对象中的参数变为模版进行传递
  • 代码示例
// 参数模板化
template<class T1, class T2>
void printPerson2(Person<T1, T2> &p) {p.showPerson();cout << "查看T1传入的数据类型:" << typeid(T1).name() << endl;cout << "查看T2传入的数据类型:" << typeid(T2).name() << endl;
}void test2() {Person<string, int> p("li", 13);printPerson2(p);
} 

类模版化

  • 将这个对象类型模板化进行传递
  • 代码示例
// 类模版化
template<class T>
void printPerson3(T &p) {p.showPerson();cout << "查看T传入的数据类型:" << typeid(T).name() << endl;
}void test3() {Person<string, int> p("ww", 18);printPerson3(p);
}

类模版和继承

  • 当子类继承的父类是一个类模板的时候,子类在声明的时候,要指出父类中T的类型

  • 如果不指定,编译器无法给子类分配内存

  • 如果想灵活指定父类中T的类型,子类也需要变为类模板

  • 代码示例

#include <iostream>using namespace std;template<class T>
class Base {
public:T m;
};// 字了继承父类时指定父类的类型
class B1 : public Base<string> {
};void test1() {B1 b;cout << "父类的类型是:" << typeid(b.m).name() << endl;
} 子类继承父类不指定父类的类型
//class B2 : public Base {
//};void test2() {// 子类继承父类不指定父类的类型不能实例化对象// error: expected class name// B2 b;
}// 子类继承父类,想灵活指定父类中T的类型,子类也需要变为类模板
template<class T1, class T2>
class B3 : public Base<T2> {
public:T1 t;
};void test3() {B3<int, int> b;cout << "父类的类型是:" << typeid(b.m).name() << endl;cout << "子类的类型是:" << typeid(b.t).name() << endl;
}int main() {test1();test2();test3();return 0;
}

类模板成员函数类外实现

#include <iostream>using namespace std;template<class T>
class AAA {
public:AAA(T a);void show();T a;
};// 类模板构造函数类外实现
template<class T>
AAA<T>::AAA(T a) {this->a = a;
}// 类模板普通函数类外实现
template<class T>
void AAA<T>::show() {cout << a << endl;
}void test() {AAA<int> Aaa(1);Aaa.show();
}int main() {test();return 0;
}

类模板分文件编写

问题

  • 按照将类声明和类实现分文件的方式,将类模版文件的声明和类实现分文件的方式,这个时候在调用时就会发生链接错误linker command failed with exit code 1

解决方法

  • 方式一:包含.cpp文件

    • 可以解决但不常用

    • 底层原理:类模板中的成员函数是在创建的时候生成的,如果只引入头文件,在调用时只会看到类及其成员函数的声明找不到实现方法;而引入cpp文件,则可以通过cpp文件中引入的头文件,以及cpp中的实现,从而解决这个问题

  • 方式二:将类模板的声明和定义都写在.hpp文件

类模板与友元

  • 实现方式

    • 全局函数类内实现

    • 全局函数内外实现

  • 代码示例

#include <iostream>using namespace std;// 需要让编译器提前知道Pp类
template<class T1, class T2>
class Pp;// 需要将全局函数的类外实现放到最前面提前让编译器知道
template<class T1, class T2>
void printPerson2(Pp<T1, T2> p) {cout << "name: " << p.name << " age: " << p.age << endl;
}template<class T1, class T2>
class Pp {
public:// 1.全局函数类内实现friend void printPerson1(Pp<T1, T2> p) {cout << "name: " << p.name << " age: " << p.age << endl;}// 2.全局函数类外实现// 加空模版参数列表,如果全局函数需要在类外实现,需要让编译器提前知道这个函数存在friend void printPerson2<>(Pp<T1, T2> p);Pp(T1 name, T2 age) {this->name = name;this->age = age;}private:T1 name;T2 age;
};void test() {Pp<string, int> p1("zsx", 18);printPerson1(p1);printPerson2(p1);
}int main() {test();return 0;
}

类模板案例

实现一个通用数组类

功能需求

  • 可以对内置数据类型以及自定义数据类型的数据进行存储

  • 将数组中的数据存储到堆区

  • 构造函数中可以传入数组的容量

  • 提供对应的拷贝构造函数以及operator=防止浅拷贝问题

  • 提供尾插法和尾删法对数组中的数据进行增加和删除

  • 可以通过下标的方式访问数组中的元素

  • 可以获取数组中当前元素个数和数组的容量

功能实现

#pragma once#include <iostream>
#include <string>using namespace std;template<class T>
class MyArray {
public:// 可以对内置数据类型以及自定义数据类型的数据进行存储// 构造函数中可以传入数组的容量MyArray(int cap) {// cout << "MyArray 有参构造函数" << endl;this->cap = cap;this->len = 0;this->pArr = new T[this->cap];}MyArray(const MyArray &ma) {// cout << "MyArray 拷贝构造函数" << endl;// 深拷贝this->pArr = new T[ma.cap];this->len = ma.len;this->cap = ma.cap;// 拷贝原来数组中的元素for (int i = 0; i < ma.len; i++) {this->pArr[i] = ma.pArr[i];}return;}// 提供对应的拷贝构造函数以及operator=防止浅拷贝问题// MyArray & 需要返回自身的引用,这样可以在使用的地方支持连等操作MyArray &operator=(const MyArray<T> &ma) {// cout << "operator=赋值运算符重载函数" << endl;// 需要先判断原来的数组中是否有元素,如果已经有了需要先将原来堆区数据释放干净if (this->pArr != NULL) {delete[] this->pArr;this->pArr = NULL;this->len = 0;this->cap = 0;}// 深拷贝this->pArr = new T[ma.cap];this->len = ma.len;this->cap = ma.cap;// 拷贝原来数组中的元素for (int i = 0; i < ma.len; i++) {this->pArr[i] = ma.pArr[i];}return *this;}// 提供尾 插法和尾删法对数组中的数据进行增加和删除void PushTail(T *elem) {if (this->len == this->cap) {cout << "数组已满,请扩容" << endl;return;}this->pArr[this->len] = *elem;this->len++;}void PopTail() {if (this->len == 0) {cout << "数组已空" << endl;return;}this->len--;}// 可以通过下标的方式访问数组中的元素// 返回&是为了可以支持链式左值操作T &operator[](int index) {return this->pArr[index];}// 可以获取数组中当前元素个数和数组的容量int GetArrLen() {return this->len;}int GetArrCap() {return this->cap;}friend void printArray(MyArray ma) {cout << "打印arr内容:";for (int i = 0; i < ma.len; i++) {cout << ma.pArr[i] << " ";}cout << endl;}// 析构函数~MyArray() {// cout << "MyArray 析构函数" << endl;if (this->pArr != NULL) {delete[] this->pArr;this->pArr = NULL;}}private:// 指针指向堆区开辟的真实数组T *pArr;// 数组中元素个数int len;// 数组容量int cap;
};

功能测试

#include "myArray.hpp"void test() {MyArray<int> ma1(10);MyArray<int> ma2(ma1);MyArray<int> ma3(100);ma3 = ma1;for (int i = 0; i < 4; i++) {ma3.PushTail(&i);}cout << ma3.GetArrLen() << endl;cout << ma3.GetArrCap() << endl;printArray(ma3);cout << ma3[2] << endl;ma3.PopTail();cout << ma3.GetArrLen() << endl;
}// 测试自定义数据类型
class PersonArr {
public:PersonArr() {}PersonArr(string name, int age) {this->name = name;this->age = age;}string name;int age;
};void printPersonArr(MyArray<PersonArr> &arr) {for (int i = 0; i < arr.GetArrLen(); i++) {cout << arr[i].name << " " << arr[i].age << endl;}cout << endl;
}void test1() {MyArray<PersonArr> arr(10);PersonArr p1("zsx1", 12);PersonArr p2("zsx2", 13);PersonArr p3("zsx3", 14);PersonArr p4("zsx4", 15);arr.PushTail(&p1);arr.PushTail(&p2);arr.PushTail(&p3);arr.PushTail(&p4);arr.PopTail();cout << arr.GetArrLen() << endl;cout << arr.GetArrCap() << endl;printPersonArr(arr);
}int main() {test();test1();return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/698625.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Redis和Mysql如何保证数据一致性

一般情况下&#xff0c;Redis用来实现应用和数据库之间读操作的缓存层&#xff0c;主要目的是减少数据 库IO&#xff0c;还可以提升数据的IO性能。 这是它的整体架构。 当应用程序需要去读取某个数据的时候&#xff0c;首先会先尝试去Redis里面加载&#xff0c;如果命中就 直…

【Java程序员面试专栏 数据结构】一 高频面试算法题:数组

一轮的算法训练完成后,对相关的题目有了一个初步理解了,接下来进行专题训练,以下这些题目就是汇总的高频题目,本篇主要聊聊数组,包括数组合并,滑动窗口解决最长无重复子数组问题,图形法解下一个排列问题,以及一些常见的二维矩阵问题,所以放到一篇Blog中集中练习 题目…

k8s(3)

目录 一.K8S的三种网络 flannel的三种模式: 在 node01 节点上操作&#xff1a; calico的 三种模式&#xff1a; flannel 与 calico 的区别&#xff1f; 二.CoreDNS 在所有 node 节点上操作&#xff1a; 在 master01 节点上操作&#xff1a; ​编辑 DNS 解析测试&#…

「C语言进阶1」动态内存分配

目录 一、动态内存分配是什么&#xff1f; 二、为什么需要动态内存分配&#xff1f; 三、怎么进行动态内存分配&#xff1f; 1. malloc 2. calloc 3. realloc a. realloc功能解析 b. 内存泄漏和内存块被截断问题 c. 总结 4. free 四、使用动态内存分配常见的问题 【面试题】 一…

如何将新标注的三元组数据转换成unicoqe可以处理的格式

目录 问题描述&#xff1a; 问题解决&#xff1a; 问题描述&#xff1a; 原始的标注的三元组格式如下&#xff1a; 需要转换的格式如下&#xff1a; tips:有一个小的难点&#xff1a; 1. 针对多三元组的情况&#xff0c;需要额外考虑 2. 最后一个样本&#xff0c;也记得需要…

QEMU之CPU虚拟化

概述 KVM是由以色列初创公司Qumranet在CPU推出硬件虚拟化之后开发的一个基于内核的虚拟机监控器。 KVM是一个虚拟化的统称方案&#xff0c;除了x86外&#xff0c;ARM等其他架构也有自己的方案&#xff0c;所以KVM的主体代码位于内核树virt/kvm目录下面&#xff0c;表示所有CP…

第九节HarmonyOS 常用基础组件25-QRCode

1、描述 用于显示单个二维码的组件。 2、接口 QRCode(value:string) 3、参数 参数名 参数类型 必填 描述 value string 是 二维码内容字符串。 4、属性 名称 参数类型 描述 color ResourceColor 设置二维码颜色。默认值&#xff1a;Color.Black backgroundCo…

阿里云优惠:优惠活动整理、云服务器价格、域名、数据库和优惠券领取

2024年阿里云优惠活动大全&#xff0c;包括阿里云服务器优惠活动清单、配置价格表、域名优惠活动、阿里云建站活动、阿里云优惠代金券免费领取、对象存储OSS活动、企业邮箱优惠、无影云电脑优惠、CDN特惠等等&#xff0c;阿里云百科aliyunbaike.com分享2024阿里云优惠活动大全_…

每日五道java面试题之spring篇(四)

目录&#xff1a; 第一题 Spring框架的设计目标&#xff0c;设计理念&#xff0c;和核心是什么&#xff1f;第二题. Spring由哪些模块组成&#xff1f;第三题. 详细讲解一下核心容器&#xff08;spring context应用上下文) 模块第四题.Spring框架中有哪些不同类型的事件第五题.…

网络中的进程监控

每个企业都有一些流程和程序来实现他们的业务目标&#xff0c;这同样适用于网络&#xff0c;网络中的进程监控是分析、处理和管理网络内发生的各种活动以提高网络性能和能力的做法。 网络中需要监控的基本进程 监视系统资源&#xff08;CPU 利用率、内存利用率、CPU 温度等&a…

【vue】如何打开别人编译后的vue项目

文件结构如下&#xff0c;编译后的文件放在dist中。 dist的文件结构大约如下&#xff0c;文件名称随项目 1.新建app.js文件 const express require(express);const app express();const port 8080;app.use(express.static(dist));app.listen(port, () > console.log); …

实用区块链应用:去中心化投票系统的部署与实施

一、需求分析背景 随着技术的发展&#xff0c;传统的投票系统面临着越来越多的挑战&#xff0c;如中心化控制、透明度不足和易受攻击等问题。为了解决这些问题&#xff0c;我们可以利用区块链技术去中心化、透明性和安全性来构建一个去中心化投票系统。这样的系统能够确保投票过…

六、回归与聚类算法 - 岭回归

目录 1、带有L2正则化的线性回归 - 岭回归 1.1 API 2、正则化程度的变化对结果的影响 3、波士顿房价预测 线性回归欠拟合与过拟合线性回归的改进 - 岭回归分类算法&#xff1a;逻辑回归模型保存与加载无监督学习&#xff1a;K-means算法 1、带有L2正则化的线性回归 - 岭回…

蓝桥杯C++竞赛常用库函数介绍

文章目录 前言一、二分查找1. 二分查找的前提2.binary_search函数3.lower_bound函数和upper_bound函数4.蓝桥杯例题 二、最值查找1. min和max函数2.min_element和max_element函数3.nth_element函数4.蓝桥杯例题 三、排序1.sort函数2.sort自定义比较函数,或lambda表达式(匿名函数…

流量分析——陇剑杯 2021【签到、jwt】

目录 签到1、攻击者正在进行的可能是什么协议的网络攻击 jwt1、该网站使用了______认证方式。前置知识&#xff1a;解&#xff1a; 2、黑客绕过验证使用的jwt中&#xff0c;id和username是3、黑客获取webshell之后&#xff0c;权限是什么4、黑客上传的恶意文件文件名是5、黑客在…

Sora没用上!国产AI创作恐怖电影:《生化危机:重生》下

Sora没用上&#xff01;国产AI创作恐怖电影&#xff1a;《生化危机&#xff1a;重生》下 丧尸围城&#xff0c;世界沦陷&#xff0c;爱丽丝是拯救这个世界的最后一剂解药&#xff0c;然而。。。 《生化危机&#xff1a;重生》&#xff08;下&#xff09;&#xff1a;在战斗的最…

物麒平台自定义事件代码修改流程

是否需要申请加入数字音频系统研究开发交流答疑群(课题组)&#xff1f;可加我微信hezkz17, 本群提供音频技术答疑服务&#xff0c;群赠送蓝牙音频&#xff0c;DSP音频项目核心开发资料, 1 配置工具对应关系 2 事件处理 3 事件定义 4

微服务远程调用Feign

目录 RPC概述 什么是Feign&#xff1f; Ribbon&Feign对比 Feign的设计架构 Spring Cloud Alibaba快速整合Feign Spring Cloud Feign扩展 日志配置 契约配置 通过拦截器实现参数传递 自定义拦截器实现认证逻辑 超时时间配置 RPC概述 微服务之间如何方便优雅的实…

来分析两道小题

一、源码 二、分析 首先它会接两个参数一个是id一个是ps&#xff0c;传递的话会包含一个flag.php&#xff0c;然后数据库连接&#xff0c;之后传递过滤&#xff0c;然后查询&#xff0c;如果查到了就会取id&#xff0c;取出来看是不是跟adog一样&#xff0c;如果是它告诉你账号…

算法------(12)Trie树(字典树)

例题&#xff1a;&#xff08;1&#xff09;Acwing 835. Trie字符串统计 Trie树是一个可以高效存储查询字符串的数据结构。将一个字符串的每一个字符作为一个根节点&#xff0c;从字符串头到字符串尾连接起来。因此我们可以把每一个字符串存储为一个节点&#xff0c;记录其子节…