天天看點

C++提高程式設計---1.1 函數模闆【P167~P173】1 模闆

C++提高程式設計---1 模闆【P167~P184】

  • 1 模闆
    • 1.1 函數模闆
      • 1.1.1 函數模闆文法
      • 1.1.2 函數模闆注意事項
      • 1.1.3 函數模闆案例
      • 1.1.4 普通函數與函數模闆差別
      • 1.1.5 普通函數與函數模闆的調用規則
      • 1.1.6 模闆的局限性

【C++ 提高程式設計主要針對 C++ 泛型程式設計和 STL技術作詳細講解,探讨C++更深層次的應用】

1 模闆

模闆就是建立通用的模具,大大提高複用性。

模闆的特點:

  • 模闆不可以直接使用,隻是一個架構;
  • 模闆雖然具有通用性,但并不是萬能的。

1.1 函數模闆

  • C++ 另一種程式設計思想被稱為泛型程式設計,主要利用的技術就是模闆
  • C++ 提供兩種模闆機制:函數模闆和類模闆

1.1.1 函數模闆文法

函數模闆作用:

建立一個通用的函數,其函數傳回值類型和形參類型可以不具體制定,用一個虛拟的類型來代表。

C++提高程式設計---1.1 函數模闆【P167~P173】1 模闆

實作整型、浮點型資料交換函數如下:

# 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 = 20;
	int b = 10;
	swapInt(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;
}

int main()
{
	test01();
	system("pause");
	return 0;
}
           
C++提高程式設計---1.1 函數模闆【P167~P173】1 模闆

雖然上述代碼可以實作相應的功能,但是如果讓你實作所有資料類型的交換實作呢?顯然一個個都實作出來是太 low 的,更何況還會有使用者自己定義的資料類型,想要全部實作的話就會顯得力不從心了。

通過觀察交換整型交換浮點型函數可以發現,兩函數存在差別的地方在于資料類型,而代碼實作都是一樣的,是以,我們可以先将資料類型部分用一個大寫字母(比如T)來表示它,後期使用的時候再告訴這個資料類型具體應該是什麼。

下面是函數模闆實作方式:

# include<iostream>
using namespace std;

// 函數模闆
template<typename T>	// 聲明一個模闆,告訴編譯器後面代碼中緊跟着的T不要報錯,T是一個通用的資料類型
void mySwap(T &a, T &b)
{
	T temp = a;
	a = b;
	b = temp;
}
// 利用函數模闆實作交換
void test02()
{
	// 兩種方式實作函數模闆調用
	// 1、自動類型推導
	int a = 20;
	int b = 10;
	mySwap(a, b);
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;

	// 2、顯示指定類型
	double c = 1.1;
	double d = 2.2;
	mySwap<double>(c, d);
	cout << "c = " << c << endl;
	cout << "d = " << d << endl;
}

int main()
{
	test02();
	system("pause");
	return 0;
}
           
C++提高程式設計---1.1 函數模闆【P167~P173】1 模闆

總結:

  • 函數模闆利用關鍵字 template;
  • 使用函數模闆有兩種方式:自動類型推導、顯示指定類型;
  • 模闆的目的是為了提高複用性,将類型參數化。

1.1.2 函數模闆注意事項

注意事項:

  • 自動類型推導,必須推導出一緻的資料類型T,才可以使用
  • 模闆必須要确定出T的資料類型,才可以使用

1.1.3 函數模闆案例

C++提高程式設計---1.1 函數模闆【P167~P173】1 模闆
# include<iostream>
using namespace std;

// 交換函數模闆
template<class T>
void mySwap(T &a, T &b)
{
	T temp = a;
	a = b;
	b = temp;
}

template<class T>
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)
		{
			mySwap(arr[max], arr[i]);
		}
	}

}

// 提供列印數組模闆
template <class T>
void printArray(T arr[], int len)
{
	for (int i = 0; i < len; i++)
	{
		cout << arr[i] << " ";
	}
	cout << endl;
}

void test01()
{
	// 測試 char 數組
	char charArr[] = "badcfe";
	int num = sizeof(charArr) / sizeof(char);
	mySort(charArr, num);
	printArray(charArr, num);
}
void test02()
{
	// 測試 int 數組
	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");
	return 0;
}
           
C++提高程式設計---1.1 函數模闆【P167~P173】1 模闆

1.1.4 普通函數與函數模闆差別

自動類型轉換==隐式類型轉換

C++提高程式設計---1.1 函數模闆【P167~P173】1 模闆

1、普通函數調用時可以發生隐式類型轉換

# include<iostream>
using namespace std;
 // 普通函數
int myAdd01(int a, int b)
{
	return a + b;
}
void test01()
{
	int a = 10;
	int b = 20;
	cout << myAdd01(a, b) << endl;

	char c = 'a';
	cout << myAdd01(a, c) << endl;
}

int main()
{
	test01();
	system("pause");
	return 0;
}
           
C++提高程式設計---1.1 函數模闆【P167~P173】1 模闆

可以看到,當輸入參數是 char 型變量時,程式也能正常運作,是在運算過程中隐式地将字元型變量轉換成了整型變量(對應的 Ascall 碼)去計算。

2、函數模闆在使用自動類型推導的時候不可以發生隐式類型轉換,而在利用指定類型的方式,可以發生隐式類型轉換

C++提高程式設計---1.1 函數模闆【P167~P173】1 模闆

可以發現函數模闆在使用自動類型推導時報錯,而采用指定類型方式不報錯。

1.1.5 普通函數與函數模闆的調用規則

C++提高程式設計---1.1 函數模闆【P167~P173】1 模闆
# include<iostream>
using namespace std;
// 普通函數
void myPrint(int a, int b)
{
	cout << "調用的普通函數" << endl;
}
// 函數模闆
template<class T>
void myPrint(T a, T b)
{
	cout << "調用的函數模闆" << endl;
}

// 重載的函數模闆
template<class T>
void myPrint(T a, T b, T c)
{
	cout << "調用的重載的函數模闆" << endl;
}

void test01()
{
	int a = 10;
	int b = 20;
	// 1、如果普通函數和函數模闆都可以實作,那麼優先調用普通函數
	myPrint(a, b);
	// 2、可以通過空模闆參數清單來強制調用函數模闆
	myPrint<>(a, b);
	// 3、函數模闆也可以發生函數重載
	myPrint(a, b, 100);
	// 4、如果函數模闆可以産生更好的比對,那麼優先調用函數模闆
	char c1 = 'a';
	char c2 = 'c';
	myPrint(c1, c2);
	/*
		我們知道雖然普通函數可以發生隐式類型轉換,但是這裡函數模闆更加比對,不用再進行隐式類型轉換了,是以優先調用函數模闆
	*/
}


int main()
{
	test01();
	system("pause");
	return 0;
}
           
C++提高程式設計---1.1 函數模闆【P167~P173】1 模闆

總結:既然已經提供了函數模闆,最好就不要再提供普通函數了,否則容易出現二義性

1.1.6 模闆的局限性

局限性:模闆的通用性不是萬能的!!

C++提高程式設計---1.1 函數模闆【P167~P173】1 模闆

是以,C++ 為了解決這種問題,提供了模闆的重載,可以為這些特定的類型提供具體化的模闆

# include<iostream>
# include<string>
using namespace std;

class Person
{
public:
	Person(string name, int age)
	{
		this->m_Name = name;
		this->m_Age = age;
	}
	string m_Name;
	int m_Age;
};

// 模闆局限性
// 模闆不是萬能的,有些特定的資料類型,還需要用具體化方式做特殊實作

template<class T>
bool myCompare(T &a, T &b)
{
	if (a == b)
	{
		return true;
	}
	else
	{
		return false;
	}
}
// 利用具體化 Person 的版本實作代碼,具體化優先調用
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");
	return 0;
}
           

總結:

  • 利用具體化的模闆,可以解決自定義類型的通用化;
  • 學習模闆不是為了寫模闆,而是在 STL 能夠運用系統提供的模闆。