- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
除了OOP外,C++另一种编程思想称为 泛型编程 ,主要利用的技术就是模板 。
C++提供两种模板机制: 函数模板 和 类模板 。
建立一个通用函数,其函数返回值类型和形参类型可以不具体制定,用一个 虚拟的类型 来代表.
template<typename T>
函数声明或定义
template --- 声明创建模板 。
typename --- 表面其后面的符号是一种数据类型,可以用class代替 。
T --- 通用的数据类型, 名称可以替换,通常为大写字母 。
举个例子,我们要写一些交换数据的函数 。
#include<iostream>
using namespace std;
//两个整形交换的函数
void swapInt(int& a, int& b) {
int temp = a;
a = b;
b = temp;
}
//交换浮点型函数
void swapDouble(double& a, double& b) {
double temp = a;
a = b;
b = temp;
}
void test01() {
int a = 10;
int b = 20;
swapInt(a, b);
cout << "a = " << a << endl;
cout << "b = " << b << endl;
}
int main() {
test01();
system("pause");
return 0;
}
很简单,但是像上面那样写函数,那交换不同的数据交换就要有对应的函数,很冗余 。
如果可以先不告诉函数输入参数的类型,用的时候再确定,就可以抽象一个通用的交换函数 。
这就是模板的用途,于是上面的例子便可以写成:
#include<iostream>
using namespace std;
//函数模板
template<typename T> //声明一个模板,后面代码里面用T的时候不要报错,T为通用数据类型
void MySawp(T& a, T& b) {
T temp = a;
a = b;
b = temp;
}
void test01() {
int a = 10;
int b = 20;
//模板有两种使用方式
//1、自动类型推导数据类型
//MySawp(a, b);
//2、显式指定数据类型
MySawp<int>(a, b);
cout << "a = " << a << endl;
cout << "b = " << b << endl;
}
int main() {
test01();
system("pause");
return 0;
}
自动类型推导,必须推导出一致的数据类型T,才可以使用 。
模板必须要确定出T的数据类型,才可以使用 。
#include<iostream>
using namespace std;
template<class T> //typename可以替换为class
void MySawp(T& a, T& b) {
T temp = a;
a = b;
b = temp;
}
//1、自动类型推导,必须推导出一致的数据类型T,才可以使用
void test01() {
int a = 10;
int b = 20;
char c = 'c';
//利用函数模板交换
//两种方式
//1、自动类型推导
MySawp(a, b);//对
//MySawp(a, c);//错,推导不出一致的T类型
cout << "a = " << a << endl;
cout << "b = " << b << endl;
}
// 2、模板必须要确定出T的数据类型,才可以使用
template<class T>
void func()//func写在template声明后面就已经是一个函数模板了
{//不管模板里面用没用T,都必须给T一个数据类型,func才可以被调用
cout << "func 调用" << endl;
}
void test02()
{
//func(); //错误,模板不能独立使用,必须确定出T的类型
func<int>(); //利用显示指定类型的方式,给T一个类型,才可以使用该模板
}
int main() {
test01();
system("pause");
return 0;
}
#include<iostream>
#include<string>
using namespace std;
//交换的函数模板
template<typename T>
void mySwap(T& a, T& b)
{
T temp = a;
a = b;
b = temp;
}
////1、先写一个选择排序的函数
//void sort(int num[],int len) {
//
// for (int i = 0; i < len; i++) {
// //以第一个元素作为初始最大值
// int max = i;
// //遍历找出最大值(的下标)
// for (int j = i + 1; j < len; j++) {
// if (num[j] > num[max]) {
// max = j;
// }
// }
// //max不等于i,出现新的max值
// //更新最大值
// if (max != i) {
// mySwap(num[max], num[i]);
// }
//
// }
//}
template<class T> // 也可以替换成typename
//利用选择排序,进行对数组从大到小的排序
void mySort(T arr[], int len)
{
for (int i = 0; i < len; i++)
{
int max = i; //最大数的下标
for (int j = i + 1; j < len; j++)
{
if (arr[max] < arr[j])
{
max = j;
}
}
if (max != i) //如果最大数的下标不是i,交换两者
{
mySwap(arr[max], arr[i]);
}
}
}
//冒泡排序,但是是从小到大
template<class T>
void bubleSort(T arr[], int len) {
T temp;
for (int i = 0; i < len - 1; i++) {
for (int j = 0; j < len - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
//打印
template<typename T>
void printArray(T arr[], int len) {
for (int i = 0; i < len; i++) {
cout << arr[i] << " ";
}
cout << endl;
}
void test01()
{
//测试char数组
char charArr[] = "bdcfeagh";
int num = sizeof(charArr) / sizeof(char);
mySort(charArr, num);
printArray(charArr, num);
}
void test02() {
//测试int数组
int intArr[] = { 7, 5, 8, 1, 3, 9, 2, 4, 6 };
int num = sizeof(intArr) / sizeof(int);
mySort(intArr, num);
printArray(intArr, num);
}
void test03() {
//测试int数组冒泡
int intArr[] = { 7, 5, 8, 1, 3, 9, 2, 4, 6 };
int num = sizeof(intArr) / sizeof(int);
bubleSort(intArr, num);
printArray(intArr, num);
}
int main() {
test03();
system("pause");
return 0;
}
普通函数与函数模板区别:
建议使用显示指定类型的方式,调用函数模板 ,因为可以自己确定通用类型T 。
建立一个通用类,类中的成员 数据类型可以不具体制定,用一个 虚拟的类型 来代表.
template<typename T>
类
template --- 声明创建模板 。
typename --- 表面其后面的符号是一种数据类型,可以用class代替 。
T --- 通用的数据类型,名称可以替换,通常为大写字母 。
#include<iostream>
using namespace std;
#include <string>
//给出类中成员属性的通用数据类型,可以直接给个默认值,后面就不用再写了
//Person为类模板,有NameType、AgeType两个通用数据类型
template<class NameType, class AgeType = int>
class Person
{
public:
Person(NameType name, AgeType age)
{
this->mName = name;
this->mAge = age;
}
void showPerson()
{
cout << "name: " << this->mName << " age: " << this->mAge << endl;
}
public:
NameType mName;
AgeType mAge;
};
void test01()
{
// 指定NameType 为string类型,AgeType 为 int类型
Person<string, int>P1("jk", 999);
P1.showPerson();
}
//类模板没有自动类型推导,必须指定数据类型
void test02()
{
// 指定NameType 为string类型,AgeType 为 int类型
Person<string> P1("dk", 9);
P1.showPerson();
}
int main() {
test01();
system("pause");
return 0;
}
类模板与函数模板区别主要有两点:
类模板和函数模板语法相似,在声明模板template后面加类,此类称为类模板 。
类模板实例化出的对象,作为参数传向函数时,一共有三种传入方式:
#include<iostream>
using namespace std;
#include <string>
#include <string>
//类模板
template<class NameType, class AgeType = int>
class Person
{
public:
Person(NameType name, AgeType age)
{
this->mName = name;
this->mAge = age;
}
void showPerson()
{
cout << "name: " << this->mName << " age: " << this->mAge << endl;
}
public:
NameType mName;
AgeType mAge;
};
//1、指定传入的类型
void printPerson1(Person<string, int>& p)
{
p.showPerson();
}
void test01()
{
Person <string, int >p("jk", 100);
printPerson1(p);
}
int main() {
test01();
system("pause");
return 0;
}
#include<iostream>
using namespace std;
#include <string>
#include <string>
//类模板
template<class NameType, class AgeType = int>
class Person
{
public:
Person(NameType name, AgeType age)
{
this->mName = name;
this->mAge = age;
}
void showPerson()
{
cout << "name: " << this->mName << " age: " << this->mAge << endl;
}
public:
NameType mName;
AgeType mAge;
};
//2、参数模板化
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 test02()
{
Person <string, int >p("nnd", 90);
printPerson2(p);
}
int main() {
test02();
system("pause");
return 0;
}
#include<iostream>
using namespace std;
#include <string>
#include <string>
//类模板
template<class NameType, class AgeType = int>
class Person
{
public:
Person(NameType name, AgeType age)
{
this->mName = name;
this->mAge = age;
}
void showPerson()
{
cout << "name: " << this->mName << " age: " << this->mAge << endl;
}
public:
NameType mName;
AgeType mAge;
};
//3、整个类模板化
template<class T>
void printPerson3(T& p)
{
cout << "T的类型为: " << typeid(T).name() << endl;
p.showPerson();
}
void test03()
{
Person <string, int >p("sb", 30);
printPerson3(p);
}
int main() {
test03();
system("pause");
return 0;
}
当类模板碰到继承时,需要注意一下几点:
#include<iostream>
using namespace std;
#include <string>
template<class T>
class Base{
T m;
};
//class Son:public Base //错误,c++编译需要给子类分配内存,必须知道父类中T的类型才可以向下继承
//简单来说,继承需要用到父类Base,Base是个类模板,那就必须指定Base中的通用数据类型
class Son :public Base<int>{ //必须指定一个类型
};
void test01(){
Son c;
}
//类模板继承类模板 ,可以用T2指定父类中的T类型
template<class T1, class T2>
class Son2 :public Base<T2>{
public:
Son2(){
cout << typeid(T1).name() << endl;
cout << typeid(T2).name() << endl;
}
T1 obj;
};
void test02(){
//class T1 == int,指定Son2维护的obj为int类型
//class T2 == char,即指定Base中的通用数据类型为char
Son2<int, char> child1;
}
int main() {
test01();
test02();
system("pause");
return 0;
}
如果父类是类模板,子类需要指定出父类中T的数据类型 。
例子,直接在单个文件中编写代码 。
#pragma once
#include<iostream>
using namespace std;
#include <string>
template<class T1, class T2>
class Person {
public:
Person(T1 name, T2 age){
this->m_Name = name;
this->m_Age = age;
}
void showPerson(){
cout << "姓名:" << this->m_Name << "年龄:" << this->m_Age << endl;
}
T1 m_Name;
T2 m_Age;
};
void test01() {
Person<string, int>p1("jk", 18);
p1.showPerson();
}
int main() {
test01();
system("pause");
return 0;
}
#pragma once
#include<iostream>
using namespace std;
#include <string>
template<class T1, class T2>
class Person {
public:
Person(T1 name, T2 age);
void showPerson();
T1 m_Name;
T2 m_Age;
};
//类外实现
template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age){
this->m_Name = name;
this->m_Age = age;
}
template<class T1, class T2>
void Person<T1, T2>::showPerson() {
cout << "姓名:" << this->m_Name << "年龄:" << this->m_Age << endl;
}
void test01() {
Person<string, int>p1("jk", 18);
p1.showPerson();
}
int main() {
test01();
system("pause");
return 0;
}
注意:加在类外实现的数据类型后面的初始化列表,里面不要再写class 。
类模板中成员函数创建时机是在调用阶段, 导致分文件编写时链接不到 。
第一种解决方式是直接包含.cpp文件,这要直接include整个.cpp文件 。
按照以前的分文件编写思路:
.h文件中要写函数、类的声明
.cpp文件通过include获取声明并实现对应函数
例如, 。
person.h 。
#pragma once
#include<iostream>
using namespace std;
#include <string>
//声明类模板
template<class T1, class T2>
class Person {
public:
Person(T1 name, T2 age);
void showPerson();
T1 m_Name;
T2 m_Age;
};
person.cpp 。
#include "person.h"
//类外实现
template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age) {
this->m_Name = name;
this->m_Age = age;
}
template<class T1, class T2>
void Person<T1, T2>::showPerson() {
cout << "姓名:" << this->m_Name << "年龄:" << this->m_Age << endl;
}
主函数 。
#pragma once
#include<iostream>
using namespace std;
#include <string>
//第一种解决方式:直接包含.cpp文件
#include "person.cpp"
void test01() {
Person<string, int>p1("jk", 18);
p1.showPerson();
}
int main() {
test01();
system("pause");
return 0;
}
像上面这样分文件编写 模板 就会遇到问题(不涉及模板就是正确的),原因如下:
如果包含的是.h,那么编译器就只知道person.h中声明的成员函数,而没有person.cpp中的实现,肯定报错,链接不上 。
既然导致错误的原因是编译器没有读到person.cpp中对应的函数实现,那直接让它读到不就完了 。
因此,一种简单粗暴的方法是:将函数的声明和实现都写在一块,然后在写有主函数的文件中通过include导入 。
实际上就是将单一文件编写的程序拆分了一下又合起来 。
person.cpp 。
#pragma once
#include<iostream>
using namespace std;
#include <string>
template<class T1, class T2>
class Person {
public:
Person(T1 name, T2 age){
this->m_Name = name;
this->m_Age = age;
}
void showPerson(){
cout << "姓名:" << this->m_Name << "年龄:" << this->m_Age << endl;
}
T1 m_Name;
T2 m_Age;
};
主函数 。
#pragma once
#include<iostream>
using namespace std;
#include <string>
//第一种解决方式:直接包含.cpp文件
#include "person.cpp"
void test01() {
Person<string, int>p1("jk", 18);
p1.showPerson();
}
int main() {
test01();
system("pause");
return 0;
}
显然,这种写法不够优雅 。
这时候有小可爱就想了,那我把声明和实现都写在.h里面不就优雅了吗?
什么你觉得还不够优雅?那把这样的.h文件改名叫.hpp,以后大家都这样写类模板,够优雅了吧?
(ps:脱裤子放屁) 。
于是便有了下面的写法,这也是涉及类模板时,常用的分文件编写方式 。
person.hpp 。
#include <string>
template<class T1, class T2>
class Person {
public:
Person(T1 name, T2 age);
void showPerson();
T1 m_Name;
T2 m_Age;
};
//类外实现
template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age) {
this->m_Name = name;
this->m_Age = age;
}
template<class T1, class T2>
void Person<T1, T2>::showPerson() {
cout << "姓名:" << this->m_Name << "年龄:" << this->m_Age << endl;
}
主函数 。
通过include导入这些实现 。
#pragma once
#include<iostream>
using namespace std;
#include <string>
//第二种解决方式:将.h和.cpp中内容写到一起,后缀改为.hpp
#include "person.hpp"
void test01() {
Person<string, int>p1("jk", 18);
p1.showPerson();
}
int main() {
test01();
system("pause");
return 0;
}
全局函数类内实现 - 直接在类内声明友元即可 。
全局函数类外实现 - 需要提前让编译器知道全局函数的存在 。
#pragma once
#include<iostream>
using namespace std;
#include <string>
template<class T1,class T2>
class Person {
//全局函数,类内实现
friend void printPerson(Person<T1, T2> &p) {
cout << "姓名: " << p.m_Name << " 年龄:" << p.m_Age << endl;
}
public:
Person(T1 name,T2 age){
this->m_Name = name;
this->m_Age = age;
}
private:
T1 m_Name;
T2 m_Age;
};
void test01() {
Person<string, int>p1("jk", 18);
printPerson(p1);
}
int main() {
test01();
system("pause");
return 0;
}
#pragma once
#include<iostream>
using namespace std;
#include <string>
//2、全局函数配合友元 类外实现 - 先做函数模板声明,下方在做函数模板定义,再做友元
template<class T1, class T2> class Person;
//如果声明了函数模板,可以将实现写到后面,否则需要将实现体写到类的前面让编译器提前看到
//template<class T1, class T2> void printPerson2(Person<T1, T2> & p);
template<class T1, class T2>
void printPerson2(Person<T1, T2>& p)
{
cout << "类外实现 ---- 姓名: " << p.m_Name << " 年龄:" << p.m_Age << endl;
}
template<class T1,class T2>
class Person {
//全局函数,类外实现
// friend void printPerson2(Person<T1, T2>& p);//记得加“<>”
// 如果类外实现,需要让编译器提前知道该函数的存在
friend void printPerson2<>(Person<T1, T2>& p);
public:
Person(T1 name,T2 age){
this->m_Name = name;
this->m_Age = age;
}
private:
T1 m_Name;
T2 m_Age;
};
////还不能写在这里,必须写在开头让编译器先看见,要不然报错
//template<class T1, class T2>
//void printPerson2(Person<T1, T2>& p) {
// cout << "类外实现的 姓名: " << p.m_Name << " 年龄:" << p.m_Age << endl;
//}
void test02() {
Person<string, int>p2("dk", 16);
printPerson2(p2);
}
int main() {
test02();
system("pause");
return 0;
}
这里又一次体现了C++作者对于套娃和"万能编译器"的喜爱 。
忘了傻逼的全局函数类外实现吧(仅限涉及模板时) 。
就老老实实用全局函数做类内实现就好 。
实现一个通用的数组类,要求如下:
分文件写法:.hpp+.cpp主函数 。
那么主要的工作应该都在.hpp中完成,具体功能则在.cpp的主函数中测试 。
先编写整体架构,提供有参构造函数和析构函数 。
//自定义通用数组类
#pragma once
#include<iostream>
using namespace std;
#include <string>
//定义类模板MyArry
template<class T>
class MyArry {
public:
//有参构造,传入容量
MyArry(int capacity) {
//cout << "MyArry有参构造" << endl;
this->m_Capacity = capacity;
this->m_Size = 0;
this->pAddress = new T[this->m_Capacity];
}
//涉及在堆中开辟空间,要写一下析构函数
//释放内存
~MyArry() {
//cout << "MyArry析构函数" << endl;
if (this->pAddress != NULL) {
delete[] this->pAddress;
this->pAddress = NULL;//防止野指针
}
}
private:
T* pAddress;//指针指向堆区开辟的真实数组
int m_Capacity;//数组容量
int m_Size;//数组大小
};
接下来逐步添加功能,上述代码已经实现了:
接下来要实现:对内置数据类型以及自定义数据类型的数据进行存储 。
这里要考虑浅拷贝问题,因此可以与第四点(拷贝构造)一块实现 。
关于浅拷贝问题,可以看看 这篇 ,后续我计划再用一篇博客讨论讨论 。
言归正传 。
//自定义通用数组类
#pragma once
#include<iostream>
using namespace std;
#include <string>
//定义类模板MyArry
template<class T>
class MyArry {
public:
//有参构造
MyArry(int capacity) {...}
//防止浅拷贝问题
//拷贝构造
MyArry(const MyArry& arr) {
//cout << "MyArry拷贝构造" << endl;
this->m_Capacity = arr.m_Capacity;
this->m_Size = arr.m_Size;
/*this->pAddress = arr.pAddress;*/
//按传进来的数组大小重新在堆区开辟空间
//深拷贝
this->pAddress = new T[arr.m_Capacity];
//将arr中的数据都拷贝过来
for (int i = 0; i < this->m_Size; i++) {
this->pAddress[i] = arr.pAddress[i];
}
}
//重载赋值运算符,防止出现浅拷贝问题
//防止写连等号时(类似这种arr[10] = arr[3])报错,所以返回类型是MyArry&,要对MyArry对象进行操作
MyArry& operator=(const MyArry& arr) {
//cout << "MyArry的operator=" << endl;
//先判断原来堆区是否有数据,有就先释放
if (this->pAddress != NULL) {
delete[] this->pAddress;
this->pAddress = NULL;
this->m_Size = 0;
}
//深拷贝
//按传进来的数组的属性初始化新的数组
this->m_Capacity = arr.m_Capacity;
this->m_Size = arr.m_Size;
this->pAddress = new T[arr.m_Capacity];
//将arr中的数据都拷贝过来
for (int i = 0; i < this->m_Size; i++) {
this->pAddress[i] = arr.pAddress[i];
}
return *this;//返回自身
}
//释放内存
~MyArry() {...}
private:
T* pAddress;//指针指向堆区开辟的真实数组
int m_Capacity;//数组容量
int m_Size;//数组大小
};
没什么好说的 。
//自定义通用数组类
#pragma once
#include<iostream>
using namespace std;
#include <string>
//定义类模板MyArry
template<class T>
class MyArry {
public:
//有参构造
MyArry(int capacity) {...}
//拷贝构造
MyArry(const MyArry& arr) {...}
//重载赋值运算符,防止出现浅拷贝问题
MyArry& operator=(const MyArry& arr) {...}
//尾插法
//输入是T类型数据,且为了防止被修改,要const修饰
void Push_Back(const T& val) {
//判断容量是否等于大小
if (this->m_Capacity == this->m_Size) {
cout << "容量过大,拷不进来" << endl;
return;
}
//往数组最后一个位置插数据,即维护的this->m_Size
this->pAddress[this->m_Size] = val;
this->m_Size++;//更新数组大小
}
//尾删法
void Pop_Back() {
//让用户访问不到最后一个元素即可,逻辑删除
//判断当前数组是否还有数据
if (this->m_Size == 0) {
cout << "没东西删" << endl;
return;
}
this->m_Size--;//屏蔽调对最后一个数的访问
}
//释放内存
~MyArry() {...}
private:
T* pAddress;//指针指向堆区开辟的真实数组
int m_Capacity;//数组容量
int m_Size;//数组大小
};
以及剩下的功能 。
//自定义通用数组类
#pragma once
#include<iostream>
using namespace std;
#include <string>
//定义类模板MyArry
template<class T>
class MyArry {
public:
//有参构造
MyArry(int capacity) {...}
//拷贝构造
MyArry(const MyArry& arr) {...}
//重载赋值运算符,防止出现浅拷贝问题
MyArry& operator=(const MyArry& arr) {...}
//尾插法
//输入是T类型数据,且为了防止被修改,要const修饰
void Push_Back(const T& val) {...}
//尾删法
void Pop_Back() {...}
//通过下标的方式访问数组中的元素
//如果调用完之后还想作为左值存在,即arr[0] = 100
//返回类型应该是T的引用,返回数的本身
T& operator[](int index) {
//返回数组中index出的元素
return this->pAddress[index];
}
//获取数组容量
int getCapacity()
{
return this->m_Capacity;
}
//获取数组大小
int getSize()
{
return this->m_Size;
}
//释放内存
~MyArry() {...}
private:
T* pAddress;//指针指向堆区开辟的真实数组
int m_Capacity;//数组容量
int m_Size;//数组大小
};
//自定义通用数组类
#pragma once
#include<iostream>
using namespace std;
#include <string>
template<class T>
class MyArry {
public:
//有参构造
MyArry(int capacity) {
//cout << "MyArry有参构造" << endl;
this->m_Capacity = capacity;
this->m_Size = 0;
this->pAddress = new T[this->m_Capacity];
}
//防止浅拷贝问题
//拷贝构造
MyArry(const MyArry& arr) {
//cout << "MyArry拷贝构造" << endl;
this->m_Capacity = arr.m_Capacity;
this->m_Size = arr.m_Size;
/*this->pAddress = arr.pAddress;*/
//按传进来的数组大小重新在堆区开辟空间
//深拷贝
this->pAddress = new T[arr.m_Capacity];
//将arr中的数据都拷贝过来
for (int i = 0; i < this->m_Size; i++) {
this->pAddress[i] = arr.pAddress[i];
}
}
//重载赋值运算符,防止出现浅拷贝问题
MyArry& operator=(const MyArry& arr) {//防止写连等号时报错,所以返回类型是MyArry&
//cout << "MyArry的operator=" << endl;
//先判断原来堆区是否有数据,有就先释放
if (this->pAddress != NULL) {
delete[] this->pAddress;
this->pAddress = NULL;
this->m_Size = 0;
}
//深拷贝
//按传进来的数组的属性初始化新的数组
this->m_Capacity = arr.m_Capacity;
this->m_Size = arr.m_Size;
this->pAddress = new T[arr.m_Capacity];
//将arr中的数据都拷贝过来
for (int i = 0; i < this->m_Size; i++) {
this->pAddress[i] = arr.pAddress[i];
}
return *this;//返回自身
}
//尾插法
//输入是T类型数据,且为了防止被修改,要const修饰
void Push_Back(const T& val) {
//判断容量是否等于大小
if (this->m_Capacity == this->m_Size) {
cout << "容量过大,拷不进来" << endl;
return;
}
//往数组最后一个位置插数据,即维护的this->m_Size
this->pAddress[this->m_Size] = val;
this->m_Size++;//更新数组大小
}
//尾删法
void Pop_Back() {
//让用户访问不到最后一个元素即可,逻辑删除
//判断当前数组是否还有数据
if (this->m_Size == 0) {
cout << "没东西删" << endl;
return;
}
this->m_Size--;//屏蔽调对最后一个数的访问
}
//通过下标的方式访问数组中的元素
//如果调用完之后还想作为左值存在,即arr[0] = 100
//返回类型应该是T的引用,返回数的本身
T& operator[](int index) {
//返回数组中index出的元素
return this->pAddress[index];
}
//获取数组容量
int getCapacity()
{
return this->m_Capacity;
}
//获取数组大小
int getSize()
{
return this->m_Size;
}
//涉及在堆中开辟空间,要写一下析构函数
//释放内存
~MyArry() {
//cout << "MyArry析构函数" << endl;
if (this->pAddress != NULL) {
delete[] this->pAddress;
this->pAddress = NULL;//防止野指针
}
}
private:
T* pAddress;//指针指向堆区开辟的真实数组
int m_Capacity;//数组容量
int m_Size;//数组大小
};
在该类中进行调用测试(自定义类的就不测了,懒) 。
#include<iostream>
using namespace std;
#include <string>
#include "MyArray.hpp"
void printIntArray(MyArry<int>& arr){
for (int i = 0; i < arr.getSize(); i++) {
cout << arr[i] << " ";
}
cout << endl;
}
void test01() {
MyArry<int> arr1(5);
/*MyArry<int> arr2(arr1);
MyArry<int> arr3(15);*/
//arr3 = arr1;
for (int i = 0; i < 10; i++)
{
arr1.Push_Back(i);//利用尾插法向数组中插数
}
cout << "array1打印输出:" << endl;
printIntArray(arr1);
cout << "array1的大小:" << arr1.getSize() << endl;
cout << "array1的容量:" << arr1.getCapacity() << endl;
cout << "--------------------------" << endl;
MyArry<int> arr2(arr1);
arr2.Pop_Back();
cout << "array2打印输出:" << endl;
printIntArray(arr2);
cout << "array2的大小:" << arr2.getSize() << endl;
cout << "array2的容量:" << arr2.getCapacity() << endl;
}
int main() {
test01();
system("pause");
return 0;
}
最后此篇关于【C++泛型编程01:模板】函数模板与类模板的文章就讲到这里了,如果你想了解更多关于【C++泛型编程01:模板】函数模板与类模板的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
C语言sscanf()函数:从字符串中读取指定格式的数据 头文件: ?
最近,我有一个关于工作预评估的问题,即使查询了每个功能的工作原理,我也不知道如何解决。这是一个伪代码。 下面是一个名为foo()的函数,该函数将被传递一个值并返回一个值。如果将以下值传递给foo函数,
CStr 函数 返回表达式,该表达式已被转换为 String 子类型的 Variant。 CStr(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CSng 函数 返回表达式,该表达式已被转换为 Single 子类型的 Variant。 CSng(expression) expression 参数是任意有效的表达式。 说明 通常,可
CreateObject 函数 创建并返回对 Automation 对象的引用。 CreateObject(servername.typename [, location]) 参数 serv
Cos 函数 返回某个角的余弦值。 Cos(number) number 参数可以是任何将某个角表示为弧度的有效数值表达式。 说明 Cos 函数取某个角并返回直角三角形两边的比值。此比值是
CLng 函数 返回表达式,此表达式已被转换为 Long 子类型的 Variant。 CLng(expression) expression 参数是任意有效的表达式。 说明 通常,您可以使
CInt 函数 返回表达式,此表达式已被转换为 Integer 子类型的 Variant。 CInt(expression) expression 参数是任意有效的表达式。 说明 通常,可
Chr 函数 返回与指定的 ANSI 字符代码相对应的字符。 Chr(charcode) charcode 参数是可以标识字符的数字。 说明 从 0 到 31 的数字表示标准的不可打印的
CDbl 函数 返回表达式,此表达式已被转换为 Double 子类型的 Variant。 CDbl(expression) expression 参数是任意有效的表达式。 说明 通常,您可
CDate 函数 返回表达式,此表达式已被转换为 Date 子类型的 Variant。 CDate(date) date 参数是任意有效的日期表达式。 说明 IsDate 函数用于判断 d
CCur 函数 返回表达式,此表达式已被转换为 Currency 子类型的 Variant。 CCur(expression) expression 参数是任意有效的表达式。 说明 通常,
CByte 函数 返回表达式,此表达式已被转换为 Byte 子类型的 Variant。 CByte(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CBool 函数 返回表达式,此表达式已转换为 Boolean 子类型的 Variant。 CBool(expression) expression 是任意有效的表达式。 说明 如果 ex
Atn 函数 返回数值的反正切值。 Atn(number) number 参数可以是任意有效的数值表达式。 说明 Atn 函数计算直角三角形两个边的比值 (number) 并返回对应角的弧
Asc 函数 返回与字符串的第一个字母对应的 ANSI 字符代码。 Asc(string) string 参数是任意有效的字符串表达式。如果 string 参数未包含字符,则将发生运行时错误。
Array 函数 返回包含数组的 Variant。 Array(arglist) arglist 参数是赋给包含在 Variant 中的数组元素的值的列表(用逗号分隔)。如果没有指定此参数,则
Abs 函数 返回数字的绝对值。 Abs(number) number 参数可以是任意有效的数值表达式。如果 number 包含 Null,则返回 Null;如果是未初始化变量,则返回 0。
FormatPercent 函数 返回表达式,此表达式已被格式化为尾随有 % 符号的百分比(乘以 100 )。 FormatPercent(expression[,NumDigitsAfterD
FormatNumber 函数 返回表达式,此表达式已被格式化为数值。 FormatNumber( expression [,NumDigitsAfterDecimal [,Inc
我是一名优秀的程序员,十分优秀!