【黑马程序员】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.hqwc.cn/news/486954.html

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

相关文章

C++:fstream用法

本文主要讲了通过fstream实现视频文件的传输过程。 #include <iostream> #include <fstream>using namespace std;int main(void) {ifstream fstrm_read("946709172.avi", ios::binary);ofstream fstrm_write("test.avi", ios::app);char vid…

网络安全笔记总结

IAE引擎 1.深度检测技术--DFI和DPI技术 DFI和DPI都是流量解析技术&#xff0c;对业务的应用、行为及具体信息进行识别&#xff0c;主要应用于流量分析及流量检测。 DPI&#xff1a;深度包检测技术 DPI是一种基于应用层的流量检测和控制技术&#xff0c;对流量进行拆包&#x…

windows下快速安装nginx 并配置开机自启动

1、下载地址&#xff1a;http://nginx.org/en/download.html 2、启动nginx 注意⚠️ 不要直接双击nginx.exe&#xff0c;这样会导致修改配置后重启、停止nginx无效&#xff0c;需要手动关闭任务管理器内的所有nginx进程。 在nginx.exe目录&#xff0c;打开命令行工具&#xf…

JVM——感谢黑马程序员官方文档

JVM——感谢黑马程序员官方文档 一、JVM介绍1.什么是JVM&#xff1f;2.有什么好处3.学习路线 二、内存结构1.程序计数器(Program Counter Registe)1.定义2.作用3.特点4.演示 2.虚拟机栈(Java Virtual Machine Stacks)1.定义2.演示3.问题解析4.栈内存溢出5.线程运行诊断&#xf…

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

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

Kotlin filterIsInstance filterNotNull forEach

Kotlin filterIsInstance filterNotNull forEach fun main(args: Array<String>) {val i1 MyItem(1, 1)val i2: MyItem? nullval i3: Int 3val i4 "4"val i5 nullval i6 MyItem(6, 6)val list mutableListOf<Any?>(i1, i2, i3, i4, i5, i6)lis…

mb和k哪个大?

在计算机和数字化领域&#xff0c;我们经常听到MB&#xff08;兆字节&#xff09;和KB&#xff08;千字节&#xff09;这两个单位。但究竟哪个更大呢&#xff1f;本文将介绍这两个单位的含义&#xff0c;并介绍使用压缩软件将文件由MB缩小为KB的方法。 1. MB和KB的含义 MB&…

VM-UNet: Vision Mamba UNet for Medical Image Segmentation

VM-UNet: 基于纯 Mamba 架构的医学图像分割模型 论文地址&#xff1a;https://arxiv.org/abs/2402.02491 项目地址&#xff1a;https://github.com/JCruan519/VM-UNet Abstract 在医学图像分割领域&#xff0c;基于CNN和基于Transformer的模型都得到了广泛的探索。然而&#…

k8s(2)

目录 一.二进制部署k8s 常见的K8S安装部署方式&#xff1a; k8s部署 二进制与高可用的区别 二.部署k8s 初始化操作&#xff1a; 每台node安装docker&#xff1a; 在 master01 节点上操作; 准备cfssl证书生成工具:&#xff1a; 执行脚本文件&#xff1a; 拉入etcd压缩包…

网工内推 | 网络安全工程师,软考认证优先,最高15K+绩效奖金

01 南京古田化工有限公司 招聘岗位&#xff1a;网络安全工程师 职责描述&#xff1a; 1. 负责公司日常网络与安全设备的实施、安装、运维、监控、巡检工作&#xff0c;如防火墙&#xff0c;交换机&#xff0c;路由器&#xff0c;VPN,WAF,IPS/IDS,抗DDOS&#xff0c;终端准入&a…

开源图表库Echarts 简介与基本使用

ECharts 是一个使用 JavaScript 实现的开源可视化图表库&#xff0c;由百度团队开发。它提供了丰富的图表类型&#xff0c;如折线图、柱状图、饼图、地图、雷达图等&#xff0c;并且可以轻松地与其他前端框架和库集成。ECharts 的设计目的是为了满足复杂数据的可视化需求&#…

v66.数组运算

1.数组的初始化 只是定义数组&#xff1a; int a[100]; 数组的集成初始化&#xff1a; int a[] {2,4,6,7,1,3,5,9,13,23,14,32};直接用大括号给出数组所有元素的初始值不需要给出数组的大小&#xff0c;编译器会运算0的补位&#xff1a; int a[4] {5}; for(int i 0;i <…