C++提高編程
本階段主要針對C++泛型編程和STT技術(shù)做詳細講解,探討C++更深層的使用
1模板
1.1模板的概念
模板就是建立通用的模具,大大提高復用性
例如生活中的模板
寸照片模板:
1.2函數(shù)模板
- C++另一種編程思想稱為 泛型編程,主要利用的技術(shù)就是模板
- C++提供兩種模板機制:函數(shù)模板和類模板
1.2.1函數(shù)模板語法
函數(shù)模板作用:
建立一個通用函數(shù),其函數(shù)返回值類型和形參類型可以不具體制定,用一個虛擬的類型來代表。
語法:
//函數(shù)聲明或定義
template<typename T>
解釋:
- template —— 聲明創(chuàng)建模板
- typename —— 表面其后面的符號是一種數(shù)據(jù)類型,可以用class代替
- T —— 通用的數(shù)據(jù)類型,名稱可以替換,通常為大寫字母
#include<iostream>;
using namespace std;
//兩個整型交換函數(shù)
void swapInt(int &a, int &b)
{
int temp = a;
a = b;
b = temp;
}
//函數(shù)模板
template<typename T>//聲明一個模板,告訴編譯器后面代碼中緊跟著的T不要報錯,T是一個通用數(shù)據(jù)類型。
void mySwap(T& a, T& b)
{
T temp = a;
a = b;
b = temp;
}
//交換兩個浮點型函數(shù)
void swapDouble(double& a, double& b)
{
double temp = a;
a = b;
b = temp;
}
//測試
void test01()
{
int a = 10;
int b = 20;
/*swapInt(a,b);*/
//利用函數(shù)模板交換
//兩種方式使用函數(shù)模板
//1、自動類型推導
//mySwap(a,b);
//2、顯示指定類型
mySwap<int>(a, b);
cout << "a=" << a << endl;
cout << "b=" << b << endl;
//double c = 1.1;
//double d = 2.2;
//swapDouble(c, d);
//cout << "c=" << c << endl;
//cout << "d=" << d << endl;
}
//函數(shù)模板
int main()
{
test01();
system("pause");//按任意鍵繼續(xù)
return 0;
}
總結(jié):
- 函數(shù)模板利用關(guān)鍵字 template
- 使用函數(shù)模板有兩種方式:自動類型推導、顯示指定類型
- 模板的目的是為了提高復用性,將類型參數(shù)化
1.2.2函數(shù)模板注意事項
注意事項:
- 自動類型推導,必須推導出---致的數(shù)據(jù)類型T,才可以使用
- 模板必須要確定出T的數(shù)據(jù)類型,才可以使用
#include<iostream>;
using namespace std;
//函數(shù)模板注意事項
template<typename T>//typename可以替換class
void mySwap(T&a, T&b)
{
T temp = a;
a = b;
b = temp;
}
//1、自動類型推導,必須推導出一致的數(shù)據(jù)類型T才可以使用。
void test01()
{
int a = 10;
int b = 20;
char c = 'c';
mySwap(a, b);//正確
//mySwap(a, c);//錯誤?。?!推導不出一致的T類型。
cout << "a=" << a << endl;
cout << "b=" << b << endl;
}
//2、模板必須要確定出T的數(shù)據(jù)類型,才可以使用。
template<typename T>//typename可以替換class
void func()
{
cout << "func 調(diào)用" << endl;
}
void test02()
{
func<int>();
}
//主函數(shù)
int main()
{
test01();
test02();
system("pause");//按任意鍵繼續(xù)
return 0;
}
總結(jié)
使用模板時必須確定出通用數(shù)據(jù)類型T,并且能夠推導出一致的類型
1.2.3函數(shù)模板案例
案例描述:
- 利用函數(shù)模板封裝一個排序的函數(shù),可以對不同數(shù)據(jù)類型數(shù)組進行排序
- 排序規(guī)則從大到小,排序算法為選擇排序
- 分別利用char數(shù)組和int數(shù)組進行測試
#include<iostream>;
using namespace std;
//實現(xiàn)通用 對數(shù)組進行排序的函數(shù)
//規(guī)則 從大到小
//算法 選擇
//測試 char 數(shù)組、int數(shù)組
//交換函數(shù)模板
template<typename T>
void mySawp(T& a, T& b)
{
T temp = a;
a = b;
b = temp;
}
//排序算法
template<typename T>
void mySort(T arr[],int len)
{
for (int i = 0; i < len; i++)
{
//認定的最大值 比 遍歷出的數(shù)值 要小,說明j下標的元素才是真正的最大值
int max = i;//認定最大值的下標
for (int j = i + 1; j < len; j++)
{
if (arr[max] < arr[j])
{
max = j;//更新最大值下標
}
}
if (max != i)
{
//交換max和i元素
mySawp(arr[max], arr[i]);
}
}
}
//打印數(shù)組的模板
template<typename T>
void printArray(T arr[], int len)
{
for (int i = 0; i < len; i++)
{
cout << arr[i] << " ";
}
cout << endl;
}
//測試
void test01()
{
//測試char數(shù)組
char charArr[] = "badcfe";
int num = sizeof(charArr) / sizeof(char);
mySort(charArr, num);
printArray(charArr, num);
}
void test02()
{
//測試int數(shù)組
int intArr[] = {7,5,1,3,9,2,4,6,8};
int num = sizeof(intArr) / sizeof(int);
mySort(intArr, num);
printArray(intArr, num);
}
int main()
{
test01();
test02();
system("pause");//按任意鍵繼續(xù)
return 0;
}
1.2.4 普通函數(shù)與函數(shù)模板的區(qū)別
普通函數(shù)與函數(shù)模板區(qū)別:
- 普通函數(shù)調(diào)用時可以發(fā)生自動類型轉(zhuǎn)換 (隱式類型轉(zhuǎn)換)
- 函數(shù)模板調(diào)用時,如果利用自動類型推導,不會發(fā)生隱式類型轉(zhuǎn)換
- 如果利用顯示指定類型的方式,可以發(fā)生隱式類型轉(zhuǎn)換
#include<iostream>;
using namespace std;
//普通函數(shù)與函數(shù)模板區(qū)別:
//1、普通函數(shù)調(diào)用可以發(fā)生隱式類型轉(zhuǎn)換
//2、函數(shù)模板 用自動類型推導,不可以發(fā)生隱式類型轉(zhuǎn)換
//3、函數(shù)模板 用顯示指定類型,可以發(fā)生隱式類型轉(zhuǎn)換
//普通函數(shù)
int myAdd01(int a, int b)
{
return a + b;
}
//函數(shù)模板
template<typename T>
T myAdd02(T a, T b)
{
return a + b;
}
void test01()
{
int a = 10;
int b = 20;
char c = 'c';//a——97 c——99;
cout << myAdd01(a, b) << endl;
cout << myAdd01(a, c) << endl;
//自動類型推導 不會發(fā)生隱式類型轉(zhuǎn)換
cout << myAdd02(a, b) << endl;
//cout << myAdd02(a, c) << endl;//錯誤!!!
//顯示指定類型 會發(fā)生隱式類型轉(zhuǎn)換
cout << myAdd02<int>(a, c) << endl;
}
int main()
{
test01();
system("pause");//按任意鍵繼續(xù)
return 0;
}
總結(jié): 建議使用顯示指定類型的方式,調(diào)用函數(shù)模板,因為可以自己確定通用類型T。
1.2.5 普通函數(shù)與函數(shù)模板的調(diào)用規(guī)則
調(diào)用規(guī)則如下:
1.如果函數(shù)模板和普通函數(shù)都可以實現(xiàn),優(yōu)先調(diào)普通函數(shù)
2.可通過空模板參數(shù)列表強制調(diào)用函數(shù)模板
3.函數(shù)模板也可以發(fā)生重載
4.如果函數(shù)模板可以產(chǎn)生更好的匹配,優(yōu)先調(diào)用函數(shù)模板
#include<iostream>;
using namespace std;
//普通函數(shù)與函數(shù)模板調(diào)用規(guī)則
//1、如果函數(shù)模板和普通函數(shù)都可以調(diào)用,優(yōu)先調(diào)用普通函數(shù)
//2、可以通過空模板參數(shù)列表 強制調(diào)用 函數(shù)模板
//3、函數(shù)模板可以發(fā)生函數(shù)重載
//4、如果函數(shù)模板可以產(chǎn)生更好的匹配,優(yōu)先調(diào)用函數(shù)模板
void myPrint(int a, int b)
{
cout << "調(diào)用的普通函數(shù)" << endl;
}
template<typename T>
void myPrint(T a, T b)
{
cout << "調(diào)用的函數(shù)模板" << endl;
}
template<typename T>
void myPrint(T a, T b,T c)
{
cout << "調(diào)用重載的函數(shù)模板" << endl;
}
void test01()
{
int a = 10;
int b = 20;
//myPrint(a, b);
//通過空模板參數(shù)列表,強制調(diào)用函數(shù)模板
myPrint<>(a, b);
myPrint(a, b,100);//函數(shù)重載
//如果函數(shù)模板產(chǎn)生更好的匹配,優(yōu)先調(diào)用函數(shù)模板
char c1 = 'a';
char c2 = 'b';
myPrint(c1,c2);//調(diào)用函數(shù)模板
}
int main()
{
test01();
system("pause");//按任意鍵繼續(xù)
return 0;
}
總結(jié): 既然提供了函數(shù)模板,最好就不要捷供普通函數(shù),否則容易出現(xiàn)二義性
1.2.6 模板的局限性
局限性:
模板的通用性并不是萬能的
#include<iostream>;
using namespace std;
#include<string>;
//模板的局限性
//模板并不是萬能的,有些特定的數(shù)據(jù)類型,需要用具體化方式做特殊實現(xiàn)
class Person
{
public:
Person(string name, int age)
{
this->m_name = name;
this->m_age = age;
}
//姓名
string m_name;
//年齡
int m_age;
};
//對比兩個數(shù)據(jù)是否相等函數(shù)
template<typename T>
bool myCompare(T& a, T& b)
{
if (a == b)
{
return true;
}
else
{
return false;
}
}
//利用具體化Person的版本實現(xiàn)代碼,具體化優(yōu)先調(diào)用
template<>bool myCompare(Person& p1, Person& p2)
{
if (p1.m_name == p2.m_name && p1.m_age == p2.m_age)
{
return true;
}
else
{
return false;
}
}
void test01()
{
int a = 10;
int b = 20;
bool ret = myCompare(a, b);
if (ret)
{
cout << "a==b" << endl;
}
else
{
cout << "a!=b" << endl;
}
}
void test02()
{
Person p1("Tom", 10);
Person p2("Tom", 10);
bool ret = myCompare(p1, p2);
if (ret)
{
cout << "p1==p2" << endl;
}
else
{
cout << "p1!=p2" << endl;
}
}
int main()
{
test01();
test02();
system("pause");//按任意鍵繼續(xù)
return 0;
}
總結(jié):
- 利用具體化的模板,可以解決自定義類型的通用化
- 學習模板并不是為了寫模板,而是在STL能夠運用系統(tǒng)提供的模板
1.3類模板
1.3.1類模板語法
類模板作用
- 建立一個通用類,類中的成員 數(shù)據(jù)類型可以不具體制定,用一個虛擬的類型來代表。
template<typename T>
類
解釋:
Template——聲明創(chuàng)建模板
Typename——表面其后面的符號是一種數(shù)據(jù)類型,可以用class代替
T——通用的數(shù)據(jù)類型,名稱可以替換,通常為大寫字母
#include<iostream>;
using namespace std;
#include<string>;
//類模板
template<class NameType,class AgeType>
class Person
{
public:
Person(NameType name, AgeType age)//成員函數(shù)
{
this->m_Name = name;
this->m_Age = age;
}
void showPerson()
{
cout << "name:"<<this->m_Name <<" age:"<<this->m_Age << endl;
}
NameType m_Name;
AgeType m_Age;
};
//測試
void test01()
{
Person<string,int> p1("孫悟空",999);
p1.showPerson();
}
int main()
{
test01();
system("pause");//按任意鍵繼續(xù)
return 0;
}
總結(jié):類模板和函數(shù)模板語法相似,在聲明模板template后面加類,此類稱為類模板。
1.3.2 類模板與函數(shù)模板區(qū)別
類模板與函數(shù)模板區(qū)別主要有兩點:
1.類模板沒有自動類型推導的使用方式
2.類模板在模板參數(shù)列表中可以有默認參數(shù)
#include<iostream>;
using namespace std;
#include<string>;
//類模板與函數(shù)模板區(qū)別主要有兩點:
template<class NameType,class AgeType = int>//僅類模板可以使用int
class Person
{
public:
Person(NameType name, AgeType age)//成員函數(shù)
{
this->m_Name = name;
this->m_Age = age;
}
void showPerson()
{
cout << "name:"<<this->m_Name <<" age:"<<this->m_Age << endl;
}
NameType m_Name;
AgeType m_Age;
};
//1.類模板沒有自動類型推導的使用方式
void test01()
{
//Person p("孫悟空", 1000);//錯誤,無法用自動類型推導
Person<string,int> p("孫悟空",1000);//正確,只能用顯示指定類型
p.showPerson();
}
//2.類模板在模板參數(shù)列表中可以有默認參數(shù)
void test02()
{
Person<string> p("豬八戒", 999);
p.showPerson();
}
int main()
{
test01();
test02();
system("pause");//按任意鍵繼續(xù)
return 0;
}
總結(jié):
- 類模板使用只能用顯示指定類型方式。
- 類模板中的模板參數(shù)列表可以有默認參數(shù)。
1.3.3 類模板中成員函數(shù)創(chuàng)建時機
類模板中成員函數(shù)和普通類中成員函數(shù)創(chuàng)建時機是有區(qū)別的:
- 普通類中的成員函數(shù)一開始就可以創(chuàng)建
- 類模板中的成員函數(shù)在調(diào)用時才創(chuàng)建
#include<iostream>;
using namespace std;
#include<string>;
//普通類中的成員函數(shù)一開始就可以創(chuàng)建
//類模板中的成員函數(shù)在調(diào)用時才創(chuàng)建
class Person1
{
public:
void showPerson1()
{
cout << "Person1 show" << endl;
}
};
class Person2
{
public:
void showPerson2()
{
cout << "Person2 show" << endl;
}
};
template<class T>
class MyClass
{
public:
T obj;
//類模板中的成員函數(shù)
void func1()
{
obj.showPerson1();
}
void func2()
{
obj.showPerson2();
}
};
//測試
void test01()
{
MyClass<Person1>m;
m.func1();
//MyClass<Person2>m;
//m.func2();
}
int main()
{
test01();
system("pause");//按任意鍵繼續(xù)
return 0;
}
總結(jié):模板中的成員函數(shù)并不是一開始就創(chuàng)建的,在調(diào)用時才去創(chuàng)建。
1.3.4 類模板對象做函數(shù)參數(shù)
學習目標:
- 類模板實例化出的對象,向函數(shù)傳參的方式
一共有三種傳入方式
1.指定傳入的類型 ?——直接顯示對象的數(shù)據(jù)類型
2.數(shù)模板化 ??????——將對象中的參數(shù)變?yōu)槟0暹M行傳遞
3.整個類模板化 ??——將這個對象類型 模板化進行傳遞
#include<iostream>;
using namespace std;
#include<string>;
//類模板對象做函數(shù)參數(shù)
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;
};
//1、指定傳入的類型——常用方式。
void printPerson1(Person<string,int>&p)//引用
{
p.showPerson();
}
void test01()
{
Person<string, int>p("孫悟空",100);
printPerson1(p);
}
//2、參數(shù)模板化
template<class T1, class T2>
void printPerson2(Person<T1,T2>&p)//引用
{
p.showPerson();
cout << "T1的類型為:" << typeid(T1).name() << endl;//查看數(shù)據(jù)中的類型命令。
cout << "T2的類型為:" << typeid(T2).name() << endl;
}
void test02()
{
Person<string, int>p("豬八戒", 90);
printPerson2(p);
}
//3、整個類模板化
template<class T>
void printPerson3( T &p )//引用
{
p.showPerson();
cout << "T的類型為:" << typeid(T).name() << endl;//查看數(shù)據(jù)中的類型命令。
}
void test03()
{
Person<string, int>p("唐僧", 30);
printPerson3(p);
}
int main()
{
test01();
test02();
test03();
system("pause");//按任意鍵繼續(xù)
return 0;
}
總結(jié):
- 通過類模板創(chuàng)建的對象,可以有三種方式向函數(shù)中進行傳參
- 使用比較止泛是第一種:指定傳入的類型
1.3.5 類模板與繼承
當類模板碰到繼承時,需要注意一下幾點:
- 當子類繼承的父類是一個類模板時,子類在聲明的時候,要指定出父類中T的類型
- 如果不指定,編譯器無法給子類分配內(nèi)存
- 如果想靈活指定出父類中T的類型,子類也需變?yōu)轭惸0?/li>
#include<iostream>;
using namespace std;
#include<string>;
//類模板與繼承
template<class T>
class Base
{
public:
T m;
};
//class Son:public Base//錯誤,必須要知道父類中的T類型,才能繼承給子類。
//1、當子類繼承的父類是一個類模板時,子類在聲明的時候,要指定出父類中T的類型
class Son1:public Base<int>//繼承
{
public:
};
//測試
void test01()
{
Son1 s1;
}
//2、如果想靈活指定出父類中T的類型,子類也需變?yōu)轭惸0?template<class T1,class T2>
class Son2 :public Base<T2>//繼承
{
public:
Son2()
{
cout << "T1的類型為:" << typeid(T1).name() << endl;
cout << "T2的類型為:" << typeid(T2).name() << endl;
}
T1 obj;
};
void test02()
{
Son2<int,char>s2;
}
int main()
{
test01();
test02();
system("pause");//按任意鍵繼續(xù)
return 0;
}
總結(jié):如果父類是類模板,子類需要指定出父類中T的數(shù)據(jù)類型。
#include<iostream>;
using namespace std;
#include<string>;
//類模板成員函數(shù)類外實現(xiàn)
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;
};
//構(gòu)造函數(shù)的類外實現(xiàn)
template<class T1, class T2>
Person<T1,T2>::Person(T1 name, T2 age)
{
this->m_Name = name;
this->m_Age = age;
}
//成員函數(shù)類外實現(xiàn)
template<class T1, class T2>
void Person<T1, T2>::showPerson()
{
cout << "姓名:" << this->m_Name << " 年齡:" << this->m_Age << endl;
}
//測試
void test01()
{
Person<string, int>P("Tom", 20);
P.showPerson();
}
int main()
{
test01();
system("pause");//按任意鍵繼續(xù)
return 0;
}
總結(jié):類模板中成員函數(shù)類外實現(xiàn)時,需要加上模板參數(shù)列表。
1.3.7 類模板分文件編寫
學習目標:
- 掌握類模板成員函數(shù)分文件編寫產(chǎn)生的問題以及解決方式
問題:
- 類模板中成員函數(shù)創(chuàng)建時機是在調(diào)用階段,導致分文件編寫時鏈接不到
解決:
- 解決方式1:直接包含.cpp源文件
- 解決方式2:將聲明和實現(xiàn)寫到同一個文件中,并更改后綴名為.hpp,hpp是約定的名稱,并不是強制
示例:
Person.hpp中代碼:
#pragma once
#include<iostream>;
using namespace std;
#include<string>;
//類模板分文件編寫問題以及解決
template<class T1, class T2>
class Person
{
public:
Person(T1 name, T2 age);
void showPerson();
public:
T1 m_Name;
T2 m_Age;
};
//構(gòu)造函數(shù)的類外實現(xiàn)
template<class T1, class T2>
Person<T1,T2>::Person(T1 name, T2 age)
{
this->m_Name = name;
this->m_Age = age;
}
//成員函數(shù)類外實現(xiàn)
template<class T1, class T2>
void Person<T1, T2>::showPerson()
{
cout << "姓名:" << this->m_Name << " 年齡:" << this->m_Age << endl;
}
類模板分文件編寫.cpp中代碼:
#include<iostream>
using namespace std;
//第一種方式,直接包含 源文件
//#include"person.cpp"
//第二種解決方式,將.h和.cpp中的內(nèi)容寫到一起,將后綴名改為.hpp文件
#include"person.hpp"
類模板分文件編寫問題以及解決
//template<class T1,class T2>
//class Person
//{
//public:
// Person(T1 name, T2 age);
// void showPerson();
// T1 m_Name;
// T2 m_Age;
//};
構(gòu)造函數(shù)的類外實現(xiàn)
//template<class T1, class T2>
//Person<T1,T2>::Person(T1 name, T2 age)
//{
// this->m_Name = name;
// this->m_Age = age;
//}
成員函數(shù)類外實現(xiàn)
//template<class T1, class T2>
//void Person<T1, T2>::showPerson()
//{
// cout << "姓名:" << this->m_Name << " 年齡:" << this->m_Age << endl;
//}
//測試
void test01()
{
Person<string, int>p("Jerry", 18);
p.showPerson();
}
int main()
{
test01();
system("pause");//按任意鍵繼續(xù)
return 0;
}
總結(jié):主流的解決方式是第二種,將類模板成員函數(shù)寫到一起,并將后綴名改為.hpp
1.3.8 類模板與友元
學習目標:
- 掌握類模板配合友元函數(shù)的類內(nèi)和類外實現(xiàn)
全局函數(shù)類內(nèi)實現(xiàn)——直接在類內(nèi)聲明友元即可
全局函數(shù)類外實現(xiàn)——需要提前讓編譯器知道全局函數(shù)的存在
#include<iostream>;
using namespace std;
#include<string>;
//類模板與友元
//通過全局函數(shù) 打印Person信息
//提前讓編譯器知道Person類存在
template<class T1, class T2>
class Person;
//類外實現(xiàn)
template<class T1, class T2>
void printPerson2(Person<T1, T2>& p)
{
cout << "類外實現(xiàn)——姓名:" << p.m_Name << " 年齡" << p.m_Age << endl;
}
template<class T1, class T2>
class Person
{
//全局函數(shù) 類內(nèi)實現(xiàn)
friend void printPerson(Person<T1,T2>p)
{
cout << "姓名:" << p.m_Name << " 年齡" << p.m_Age << endl;
}
//全局函數(shù) 類外實現(xiàn)
//加空模板參數(shù)列表<>
//如果全局函數(shù) 是類外實現(xiàn),需要讓編譯器提前知道這個函數(shù)的存在
friend void printPerson2<>(Person<T1, T2>& p);//普通函數(shù)聲明
public:
Person(T1 name, T2 age)
{
this->m_Name = name;
this->m_Age = age;
}
private:
T1 m_Name;
T2 m_Age;
};
//1、全局函數(shù)在類內(nèi)實現(xiàn)
void test01()
{
Person<string, int>p("Tom", 20);
printPerson(p);
}
//2、全局函數(shù)在類外實現(xiàn)
void test02()
{
Person<string, int>p("Jerry", 20);
printPerson2(p);
}
int main()
{
test01();
test02();
system("pause");//按任意鍵繼續(xù)
return 0;
}
總結(jié):建議全局函教做類內(nèi)實現(xiàn),用法簡單,而且編譯器可以直接識別
1.3.9 類模板案例
案例描述:實現(xiàn)一個通用的數(shù)組類,要求如下:
- 可以對內(nèi)置數(shù)據(jù)類型以及自定義數(shù)據(jù)類型的數(shù)據(jù)進行存儲
- 將數(shù)組中的數(shù)據(jù)存儲到堆區(qū)
- 構(gòu)造函數(shù)中可以傳入數(shù)組的容量
- 提供對應(yīng)的拷貝構(gòu)造函數(shù)以及operator=防止淺拷貝問題
- 提供尾插法和尾刪法對數(shù)組中的數(shù)據(jù)進行增加和刪除
- 可以通過下標的方式訪問數(shù)組中的元素
- 可以獲取數(shù)組中當前元素個數(shù)和數(shù)組的容量
思路分析:
?MyArrey.hpp中的代碼:
//自己的通用的數(shù)組類
#pragma once
#include<iostream>
using namespace std;
template<class T>
class MyArrey
{
public:
//有參構(gòu)造 參數(shù) 容量
MyArrey(int capacity)
{
cout << "MyArrey有參構(gòu)造調(diào)用" << endl;
this->m_Capacity = capacity;
this->m_Size = 0;
this->pAddress = new T[this->m_Capacity];
}
//拷貝構(gòu)造
MyArrey(const MyArrey& arr)
{
cout << "MyArrey拷貝構(gòu)造調(diào)用" << 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中的數(shù)據(jù)都拷貝過來
for (int i = 0; i < this->m_Size; i++)
{
this->pAddress[i] = arr.pAddress[i];
}
}
//operator= 防止淺拷貝問題 a = b = c
MyArrey& operator=(const MyArrey& arr)
{
cout << "MyArrey 的 operator= 調(diào)用" << endl;
//判斷原來堆區(qū)是否有數(shù)據(jù),如果有先釋放
if (this->pAddress != NULL)
{
delete[] this->pAddress;
this->pAddress = NULL;
this->m_Capacity = 0;
this->m_Size = 0;
}
//深拷貝
this->m_Capacity = arr.m_Capacity;
this->m_Size = arr.m_Size;
this->pAddress = new T[arr.m_Capacity];
//將arr中的數(shù)據(jù)都拷貝過來
for (int i = 0; i < this->m_Size; i++)
{
this->pAddress[i] = arr.pAddress[i];
}
return *this;
}
//析構(gòu)函數(shù)
~MyArrey()
{
if (this->pAddress!=NULL)
{
cout << "MyArrey析構(gòu)函數(shù)調(diào)用" << endl;
delete[] this->pAddress;
this->pAddress = NULL;
}
}
private:
T* pAddress;//指針指向堆區(qū)開辟的真實數(shù)組
int m_Capacity;//數(shù)組的容量
int m_Size;//數(shù)組大小
};
類模板案例-數(shù)組類封裝.cpp中的代碼:
#include<iostream>;
using namespace std;
#include<string>;
#include"MyArray.hpp"
void test01()
{
MyArrey<int>arr1(5);
MyArrey<int>arr2(arr1);
MyArrey<int>arr3(100);
arr3 = arr1;
}
int main()
{
test01();
system("pause");//按任意鍵繼續(xù)
return 0;
}
尾插法/尾刪法——案例完整代碼:
MyArrey.hpp中的代碼:
//自己的通用的數(shù)組類
#pragma once
#include<iostream>
using namespace std;
template<class T>
class MyArray
{
public:
//有參構(gòu)造 參數(shù) 容量
MyArray(int capacity)
{
cout << "MyArray有參構(gòu)造調(diào)用" << endl;
this->m_Capacity = capacity;
this->m_Size = 0;
this->pAddress = new T[this->m_Capacity];
}
//拷貝構(gòu)造
MyArray(const MyArray& arr)
{
cout << "MyArray拷貝構(gòu)造調(diào)用" << 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中的數(shù)據(jù)都拷貝過來
for (int i = 0; i < this->m_Size; i++)
{
this->pAddress[i] = arr.pAddress[i];
}
}
//operator= 防止淺拷貝問題 a = b = c
MyArray& operator=(const MyArray& arr)
{
cout << "MyArray 的 operator= 調(diào)用" << endl;
//判斷原來堆區(qū)是否有數(shù)據(jù),如果有先釋放
if (this->pAddress != NULL)
{
delete[] this->pAddress;
this->pAddress = NULL;
this->m_Capacity = 0;
this->m_Size = 0;
}
//深拷貝
this->m_Capacity = arr.m_Capacity;
this->m_Size = arr.m_Size;
this->pAddress = new T[arr.m_Capacity];
//將arr中的數(shù)據(jù)都拷貝過來
for (int i = 0; i < this->m_Size; i++)
{
this->pAddress[i] = arr.pAddress[i];
}
return *this;
}
//尾插法20230817
void Push_Back(const T & val)
{
//判斷容量是否等于大小
if (this->m_Capacity == this->m_Size)
{
return;
}
this->pAddress[this->m_Size] = val;//在數(shù)組末尾插入數(shù)據(jù)
this->m_Size++;//更新數(shù)組大小
}
//尾刪法
void Pop_Back()
{
//讓用戶訪問不到最后一個元素,即為尾刪,邏輯刪除。
if (this->m_Size == 0)
{
return;
}
this->m_Size--;
}
//通過下標方式訪問數(shù)組中的元素 arr[0]=100。//重載operator
T& operator[](int index)//下標
{
return this->pAddress[index];
}
//返回數(shù)組的容量
int getCapacity()
{
return this->m_Capacity;
}
//返回數(shù)組的大小
int getSize()
{
return this->m_Size;
}
//析構(gòu)函數(shù)
~MyArray()
{
if (this->pAddress!=NULL)
{
cout << "MyArray析構(gòu)函數(shù)調(diào)用" << endl;
delete[] this->pAddress;
this->pAddress = NULL;
}
}
private:
T* pAddress;//指針指向堆區(qū)開辟的真實數(shù)組
int m_Capacity;//數(shù)組的容量
int m_Size;//數(shù)組大小
};
類模板案例-數(shù)組類封裝.cpp中的代碼:
#include<iostream>;
using namespace std;
#include<string>;
#include"MyArray.hpp"
void printIntArray(MyArray<int>&arr)
{
for (int i = 0; i < arr.getSize(); i++)
{
cout << arr[i] << endl;
}
}
void test01()
{
MyArray<int>arr1(5);
for (int i = 0; i < 5; i++)
{
//利用尾插法向數(shù)組中插入數(shù)據(jù)
arr1.Push_Back(i);
}
cout << "arr1的打印輸出為:" << endl;
printIntArray(arr1);
cout << "arr1的容量為:" << arr1.getCapacity() << endl;
cout << "arr1的大小為:" << arr1.getSize() << endl;
MyArray<int>arr2(arr1);
cout << "arr2的打印輸出為:" << endl;
printIntArray(arr2);
//尾刪
arr2.Pop_Back();
cout << "arr2尾刪后:" << endl;
cout << "arr2的容量為:" << arr2.getCapacity() << endl;
cout << "arr2的大小為:" << arr2.getSize() << endl;
/*MyArray<int>arr3(100);
arr3 = arr1;*/
}
//測試自定義的數(shù)據(jù)類型
class Person
{
public:
Person() {};
Person(string name, int age)
{
this->m_Name = name;
this->m_Age = age;
}
string m_Name;
int m_Age;
};
void printPersonArray(MyArray<Person> &arr)
{
for (int i = 0; i < arr.getSize(); i++)
{
cout << "姓名:" << arr[i].m_Name << "年齡" << arr[i].m_Age << endl;
}
}
void test02()
{
MyArray<Person> arr(10);
Person p1("孫悟空",999);
Person p2("韓信", 30);
Person p3("妲己", 20);
Person p4("趙云", 25);
Person p5("安其拉", 27);
//將數(shù)據(jù)插入到數(shù)組中
arr.Push_Back(p1);
arr.Push_Back(p2);
arr.Push_Back(p3);
arr.Push_Back(p4);
arr.Push_Back(p5);
//打印數(shù)組
printPersonArray(arr);
//輸出容量
cout << "arr的容量為:" << arr.getCapacity() << endl;
//輸出大小
cout << "arr的大小為:" << arr.getSize() << endl;
}
int main()
{
test01();
test02();
system("pause");//按任意鍵繼續(xù)
return 0;
}
總結(jié):
能夠利用所學知識點實現(xiàn)通用的數(shù)組文章來源:http://www.zghlxwxcb.cn/news/detail-662501.html
模板結(jié)束。文章來源地址http://www.zghlxwxcb.cn/news/detail-662501.html
到了這里,關(guān)于C++提高編程——模板的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!