c++: 泛型編程(函數模板、模板機制剖析、模板的侷限性、類模板)

c++提供了函數模板(function template.)所謂函數模板,實際上是建立一個通用函數,其函數類型和形參類型不具體制定,用一個虛擬的類型來代表。這個通用函數就成爲函數模板。凡是函數體相同的函數都可以用這個模板代替,不必定義多個函數,只需在模板中定義一次即可。

  • c++提供兩種模板機制:函數模板類模板

目錄

一、函數模板

1.1 函數模板和普通函數區別

1.2 函數模板和普通函數在一起調用規則

二、模板機制剖析

2.1編譯過程

2.2 模板實現機制

2.3模板的侷限性

三、類模板

3.1 類模板做函數參數

3.2 類模板派生普通類

3.3 類模板頭文件和源文件分離問題

3.4 模板類碰到友元函數(類內實現)


 

 

一、函數模板

語法:

template< typename  T >                                             T是通用的數據類型

函數名(T&形參1 T&形參2....){ 函數實現 }

 

1.1 函數模板和普通函數區別

  1. 函數模板不允許自動類型轉化,必須嚴格匹配類型。
  2. 普通函數能夠自動進行類型轉化

 

1.2 函數模板和普通函數在一起調用規則

  1. c++編譯器優先考慮普通函數
  2. 如果想強制調用函數模板,需要加 空模板參數列表
  3. 函數模板可以像普通函數那樣可以被重載
  4. 如果函數模板可以產生一個更好的匹配(不發生類型轉化),那麼選擇模板
void myPrint(int a, int b)
{
	cout << "普通函數myPrint調用" << endl;
}

template<class T>
void myPrint(T a, T b)
{
	cout << "函數模板myPrint調用" << endl;
}

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

void test02()
{
	//1、如果普通函數和函數模板都可以匹配,優先使用普通函數
	int a = 10;
	int b = 20;
	myPrint(a, b);

	//2、如果想強制調用函數模板,需要加 空模板參數列表
	myPrint<>(a, b);

	//3、函數模板也可以發生函數重載
	myPrint(a, b, 10);

	//4、如果函數模板可以產生更好的匹配,那麼優先使用函數模板
	char c1 = 'c';
	char c2 = 'd';
	myPrint(c1, c2);

}

 

二、模板機制剖析

2.1編譯過程

hello.cpp程序是高級c語言程序,這種程序易於被人讀懂。爲了在系統上運行hello.c程序,每一條c語句都必須轉化爲低級的機器指令。然後將這些機器指令打包成可執行目標文件格式,並以二進制形式存儲於磁盤中。

預處理(Pre-processing) -> 編譯(Compiling) ->彙編(Assembling) -> 鏈接(Linking)

 

2.2 模板實現機制

函數模板機制結論:

  1. 編譯器並不是把函數模板處理成能夠處理任何類型的函數
  2. 函數模板通過具體類型產生不同的函數
  3. 編譯器會對函數模板進行兩次編譯第一次在聲明的地方對模板代碼本身進行編譯,第二次在調用的地方對參數替換後的代碼進行編譯。

 

2.3模板的侷限性

 

函數模板並不是萬能,對於自定義類型數據,有些情況不能夠正常使用

解決方法:可以利用具體化實現

語法:template <>  返回值類型  函數名 (處理數據類型..)

例子:

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)
{
	return a == b;
}
//具體語法實現
template<>  bool myCompare(Person &a, Person&b)
{
	cout << "具體化實現" << endl;
	if (a.m_Name == b.m_Name && a.m_Age == b.m_Age)
	{
		return true;
	}
	return false;
}

void test02()
{
	Person p1("Tom", 10);
	Person p2("Tom", 10);

	bool ret = myCompare(p1, p2);
	if (ret)
	{
		cout << "p1==p2" << endl;
	}
}

 

三、類模板

類模板和函數模板的定義和使用類似,我們已經進行了介紹。有時,有兩個或多個類,其功能是相同的,僅僅是數據類型不同。

例子:

//可以使用默認參數
template<class NAMETYPE , class AGETYPE = int>
class Person
{
public:
	Person(NAMETYPE name, AGETYPE age)
	{
		this->m_Name = name;
		this->m_Age = age;
	}

	void showPerson()
	{
		cout << "姓名: " << this->m_Name << " 年齡: " << this->m_Age << endl;
	}

	NAMETYPE m_Name;
	AGETYPE m_Age;
};

void test01()
{
	//Person p1("Tom", 20);  類模板使用時候,不可以用自動類型推導,只能用顯示指定類型
	Person <string>p1("Tom", 20);
	p1.showPerson();
}

 

3.1 類模板做函數參數

可以有3中情況:

  • 1、指定傳入類型
  • 2、將參數模板化
  • 3、將類模板化
//模板中 也可以使用默認參數
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 doWork(Person <string, int>&p)
{
	p.showPerson();
}

void test01()
{
	Person <string,int>p1("Tom", 100);
	doWork(p1);
}

//2、將參數模板化
template<class T1,class T2>
void doWork2(Person <T1, T2>&p)
{
	cout << "T1 = " << typeid(T1).name() << endl;
	cout << "T2 = " << typeid(T2).name() << endl;
	p.showPerson();
}

void test02()
{
	Person <string, int>p1("Jerry", 100);
	doWork2(p1);
}


//3、將類模板化
template<class T>
void doWork3(T &p)
{
	cout << "T = " << typeid(T).name() << endl;
	p.showPerson();
}

void test03()
{
	Person <string, int>p1("Bill", 100);
	doWork3(p1);
}

 

3.2 類模板派生普通類

  • 子類在繼承時,必須確定出父類的T的數據類型,否則無法給T分配內存空間
//類模板
template<class T>
class MyClass{
public:
	MyClass(T property){
		this->mProperty = property;
	}
public:
	T mProperty;
};

//子類實例化的時候需要具體化的父類,子類需要知道父類的具體類型是什麼樣的
//這樣c++編譯器才能知道給子類分配多少內存

//普通派生類
class SubClass : public MyClass<int>{
public:
	SubClass(int b) : MyClass<int>(20){
		this->mB = b;
	}
public:
	int mB;
};

 

3.3 類模板頭文件和源文件分離問題

類模板的聲明和實現放到一個文件中,我們把這個文件命名爲.hpp(這個是個約定的規則,並不是標準,必須這麼寫).

原因:

  1. 類模板需要二次編譯,在出現模板的地方編譯一次,在調用模板的地方再次編譯。
  2. C++編譯規則爲獨立編譯。

 

3.4 模板類碰到友元函數(類內實現)

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>p("Tom", 111);

	printPerson(p);
}

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章