- 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的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
namespace std { template <> class hash{ public : size_t operator()( cons
我正在构建一个 Javascript 交互性有限的 Django 应用程序,并且正在研究如何将 Vue 模板与 Django 模板合并以实现相同的内容。 想象一个无限滚动的页面,其中 SEO 非常重要
我需要一个由游戏逻辑组成的外部类,调用 LitElement 组件,并向其传递一个 html 模板文字,该组件将使用该文字来更新其自己的 html 模板文字的一部分。 在下面的代码中,您将看到组件的一
很简单,我不想在 html 文件中定义所有 Handlebars 模板 我试过了 但这并没有奏效。我是否可以不以编程方式定义模板,甚至只是加载 Handlebars 文件,以便我可以重用,而且我觉得
在此代码中,j 正确地成为对象:j.name、j.addr、j.city、j.state 和 j.zip。但是,成功函数有一个 JavaScript 错误 .tmpl() 不是函数。 {{t
Django模板不会?点进来,总结了模板语法传值取值、过滤器和自定义过滤器、模板标签的分类、中间件403报错如何解决、如何继承模板~👆 Django 模板 模板传值取值 后端传值 键值对形式:{‘n
哈喽大家好,我是鹿 九 丸 \color{red}{鹿九丸}鹿九丸,今天给大家带来的是C++模板。 如果大家在看我的博客的过程中或者学习的过程中以及在学习方向上有什么问题或者想跟我交流的话可以加我的企
我正在用 PHP 编写一个简单的模板层,但我遇到了一些困难。目前它是这样工作的: 首先,我使用 fetch_template 从数据库中加载模板内容 - 这可行(如果您有兴趣,我会在启动时收集所有模板
我正在制作有关模板的 Django 教程。我目前处于此代码: from django.template import Template, Context >>> person = {'name': '
我正在使用 Jquery 模板来显示传入的 JSON 数据我想将模板加载到可缓存的外部文件中。我该怎么做? 更新 http://encosia.com/2010/12/02/jquery-templa
这是我的观点.py: from django.http import HttpResponse from django.template.loader import get_template from
我试图说服一位同事在项目的前端使用 Mustache/Hogan,我提出了以下建议: 有一个 templates.js 文件,大致如下所示: var tpl_alert = '{{msg}}'; va
我想创建一个通用的数组函数。在我的 API 中,我有一个通用容器,我需要将其转换为正确的类,但我想让它通用 template void UT::printArray(CCArray* arr, T t
有谁知道是否有办法在 Genshi 中创建 javascript 模板?我的意思是,我需要一个 .js 文件,可以在其中使用 等指令。等等。 有什么想法吗?谢谢! 最佳答案 你可以直接在html中这
我想知道是否可以设置某种 HTML 模板系统,基本上我有 3 个不同的文件: - header.html - footer.html - landing.html(landing.html 是包含页面
我正在尝试构建以下 HTML 模板: 这很简单,如果我使用红色容器 1-4,语法如下: 1 2 3 4 5 6 7 8 9 https://jsfi
#include "boost/numeric/ublas/matrix.hpp" using namespace boost::numeric::ublas; template class Lay
我在一个类中有一个函数,它传递了一个函数及其参数,然后将它们绑定(bind)到一个函数调用中并调用该函数等。 这已经被快速组合在一起以测试我知道代码不是很好的概念。 class Profiling {
是否有一个 c++ 结构或模板(在任何库中)允许我在十进制和任何其他基数之间进行转换(很像 bitset 可以做的)? 最佳答案 是的,你可以使用unsigned int: unsigned int
数据类型给程序设计带来的困扰及解决方案 int maxt(int, int); double maxt(double, double); 若有一种占位符T,能够代替类型,便可以简化代码的冗余编写
我是一名优秀的程序员,十分优秀!