C++泛型编程基础

泛型编程的作用

我们通过具体的例子来理解,假设我们要实现如下需求:

实现函数用来返回两个数的最大值,要求能支持char类型、int类型、double类型变量

我们可以设计出如下函数

int Max(int a, int b)
{
	return a>b ? a:b;
}

char Max(char a, char b)
{
	return a>b ? a:b;
}

float Max(float a, float b)
{
	return a>b ? a:b;
}

但其中存在许多重复的地方,除了数据类型其他地方一模一样,效率就显得很低下。

为了提高开发效率,于是有了泛型编程,我们用函数模版来实现开始的需求,如下

template 
T Max(T a, T b){
	return a>b ? a:b;
}

其中T可以是任意的数据类型,极大提高了开发效率

函数模版由以下三部分组成:  模板说明 + 函数定义 + 函数模板调用

  template < 类型形式参数表 >

  类型  函数名 (形式参数表)

{

    //语句序列

}

注意点:不同对象的T类型只能是同一种数据类型

函数模版和普通函数的重载

#include
using namespace std;

template 
void add(T a, T b) {
	cout << a + b << endl;
	cout << "调用了模板版本的add()" << endl;
}
void add(int a, int b) {
	cout << a + b << endl;
	cout << "调用了int版本的add()" << endl;
}

int main() {
	int a = 1, b = 4;
	double c = 2.5, d = 3.14;
	add(a, b);
	add(a, b);
	return 0;
}

如上所示,如果有普通函数匹配上了具体的数据类型,则会调用普通重载函数,但若在函数名后加上数据类型如(数据类型为空也可以),则会调用函数模版

注意:

1. 编译器并不是把函数模板处理成能够处理任意类型的函数

2. 编译器从函数模板通过具体类型产生不同的函数

类模板的定义

template 
class A
{
public:
	A(T t)
	{
		this->t = t;
	}

	T &getT()
	{
		return t;
	}

public:
	T t;
};

模板类定义类对象,必须显示指定类型

#include
using namespace std;

template 
class A {
public:
	A(T a, T b) {
		this->a = a;
		this->b = b;
		cout << "构造函数" << endl;
	}
	void print() {
		cout << "a = " << a << " b = " << b << endl;
	}
private:
	T a, b;
};


int main() {
	int a = 1, b = 4;
	double c = 2.5, d = 3.14;
	A obj1(a, b);
	return 0;
}

类模板的继承

父类是模板类,子类是普通类

template 
class A {
public:
	A(T a, T b) {
		this->a = a;
		this->b = b;
		cout << "构造函数" << endl;
	}
private:
	T a, b;
};

class B :public A {

};

需要具体指出数据类型

父类是普通类,子类是模板类

class B  {

};
template 
class A : public B {
public:
	A(T a, T b) {
		this->a = a;
		this->b = b;
		cout << "构造函数" << endl;
	}
private:
	T a, b;
};

和普通类的继承类似

父类和子类都是模板类

template 
class A  {
public:
	A(T a, T b) {
		this->a = a;
		this->b = b;
		cout << "构造函数A" << endl;
	}
	void print() {
		cout << "a=" << a << " b=" << b << endl;
	}
protected:
	T a, b;
};

template
class B :public A {
public:
	B(C c) :A(1, 2) {
		this->c = c;

		cout << "构造函数B" << endl;
		cout << "c=" << c << endl;
		cout << "a=" << this->a << " b=" << this->b << endl;
}
private:
	C c;
	
};

子类从模板类继承的时候,需要让编译器知道父类的数据类型具体是什么

类模板函数的表达方式

#pragma once
#include 
using namespace std;
template 
class A
{
public:
	A(T t = 0);

	T& getT();

	A operator +(const A& other);

	void print();

private:
	T t;
};




#include "A.h"

template
void A::print()
{
	cout << this->t << endl;
}

template
A::A(T t)
{
	this->t = t;
}

template
T& A::getT()
{
	return t;
}

template
A A::operator+(const A& other)
{
	A tmp;
	tmp.t = this->t + other.t;
	return tmp;
}
#include
#include"A.h"
#include"A.cpp"
using namespace std;

int main() {
	A a(10),b(20);
	A c = a + b;
	cout << c.getT() << endl;
	c.print();
	return 0;
}

当我们的类声明文件和实现函数分离时,由于类模板的特殊性,在main函数中我们也要#.cpp头文件,否则系统将找不到实现函数。

注意:

  1. 函数前声明 template    <类型形式参数表>
  2. 类的成员函数前的类限定域说明必须要带上虚拟参数列表
  3. 返回的变量是模板类的对象时必须带上虚拟参数列表
  4. 成员函数参数中出现模板类的对象时必须带上虚拟参数列表
  5. 成员函数内部没有限定   

友元函数的实现

template
A operator+(const A& a, const A& b)
{
	A tmp;
	tmp.t = a.t + b.t;
	return tmp;
	cout << "友元函数" << endl;
}

友元函数的调用

int main() {
	A a(10),b(20);
	A c = a + b;
	cout << c.getT() << endl;
	c.print();
	return 0;
}

静态对象的定义和调用

#include
#include"A.h"
#include"A.cpp"
using namespace std;

template
class C {
public:
	static int count;
};

template int C::count = 100;

int main() {
	cout << C::count << endl;
	return 0;
}

模板类总结

  1. 写出一个实际的类
  2. 将类中的数据类型替换为模版的类型
  3. 在类的前面加上模版类型名:template

注意:

可以使用多个虚拟类型名,但每个前面都要加上typename

在定义对象时分别代入实际的类型名如:someclass object;

你可能感兴趣的:(c++,开发语言)