【C/C++学院】(11)泛型编程/函数模板/类模板

1.泛型编程基础

#include "iostream"
using namespace std;
void swap(int &a, int &b)
{
    int c;
    c = a;
    a = b;
    b = c;
}
void swap(float &a, float &b)
{
    float c;
    c = a;
    a = b;
    b = c;
}
void main()
{
    int a = 1, b = 2;
    swap(a, b);
    float a1 = 1, b1 = 2;
    swap(a1, b1);
    system("pause");
}
#include "iostream"
using namespace std;
//template关键字告诉c++编译器,现在开始泛型编程
//typename 告诉c++编译器,T为类型(T为类型,可以参数化,int float),你不要乱报错
//类型参数化。。。。。。。
template<typename T>
void swap2(T &a, T &b)
{
    T c;
    c = a;
    a = b;
    b = c;
}
void  main()
{
    //泛型编程的调用方式有两种
    //自动类型推导
    int x = 1, y = 2;
    swap2(x, y);
    printf("x:%d y:%d \n", x, y);
    float x1 = 1.0, y1 = 2.0;
    //具体类型调用
    swap2<float>(x1, y1);
    printf("x1:%f y1:%f \n", x1, y1);
    system("pause");
}

2.函数模板加强

#include "iostream"
using namespace std;
template<typename T>
void sortArray(T *a, int num)
{
    int i = 0, j = 0;
    T tmp;
    for (i = 0; i<num; i++)
    {
        for (j = i; j<num; j++)
        {
            if (a[i] < a[j])
            {
                tmp = a[i];
                a[i] = a[j];
                a[j] = tmp;
            }
        }
    }
}
template<class T>
void printfArray(T *a, int num)
{
    cout << endl;
    for (int i = 0; i<num; i++)
    {
        cout << a[i] << " ";
    }
}
void main()
{
    int a[10] = { 1, 3, 4, 5, 2, 3, 44, 6, 3 };
    int num = sizeof(a) / sizeof(*a);
    sortArray<int>(a, num);
    printfArray<int>(a, num);
    char buf[] = "163addeadfdsafdsaf";
    int len = strlen(buf);
    sortArray<char>(buf, len);
    printfArray<char>(buf, len);
    system("pause");
}

3.
函数模板遇上函数重载

函数模板可以像普通函数一样被重载

C++编译器优先考虑普通函数

如果函数模板可以产生一个更好的匹配,那么选择模板

可以通过空模板实参列表的语法限定编译器只通过模板匹配

/*
1 函数模板可以像普通函数一样被重载
2 C++编译器优先考虑普通函数
3 如果函数模板可以产生一个更好的匹配,那么选择模板
4 可以通过空模板实参列表的语法限定编译器只通过模板匹配
*/
/*
函数模板不允许自动类型转化
普通函数能够进行自动类型转换
*/
#include <iostream>
using namespace std;
int Max(int a, int b)
{
    cout << "int Max(int a, int b)" << endl;
    return a > b ? a : b;
}
template<typename T>
T Max(T a, T b)
{
    cout << "T Max(T a, T b)" << endl;
    return a > b ? a : b;
}
template<typename T>
T Max(T a, T b, T c)
{
    cout << "T Max(T a, T b, T c)" << endl;
    return Max(Max(a, b), c);
}
void main()
{
    int a = 1;
    int b = 2;
    cout << Max(a, b) << endl;
    cout << Max<>(a, b) << endl;
    cout << Max(3.0, 4.0) << endl;
    cout << Max(5.0, 6.0, 7.0) << endl;
    cout << Max('a', 100) << endl;
    system("pause");
    return;
}

4.函数模板本质探究:

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

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

编译器会对函数模板进行两次编译

在声明的地方对模板代码本身进行编译

在调用的地方对参数替换后的代码进行编译

#include "cstdlib"
using namespace std;
/*
函数模板的深入理
― 编译器并不是把函数模板处理成能够处理任意类型的函数
― 编译器从函数模板通过具体类型产生不同的函数
― 编译器会对函数模板进行两次编译
―在声明的地方对模板代码本身进行编译
―在调用的地方对参数替换后的代码进行编译
*/
//template告诉编译器,这里开始进行泛型编程
//typename告诉编译器,类型名称为T 编译器你看到类型T 不要乱报错。。。。
//T为类型,类型参数化而已
template<typename T>
void swap2(T &a, T &b)
{
    T t = a;
    a = b;
    b = t;
}
int main()
{
    int x = 1;
    int y = 2;
    //泛型编程的调用方式分为两种
    //自动类型 推导调用
    swap2<int>(x, y);
    //printf("\n%d, %d", x, y);
    float x1 = 1.0;
    float y1 = 2.0;
    //具体类 显示调用
    swap2<float>(x1, y1);
    //printf("\n%f, %f", x1, y1);
    cout << "hello...." << endl;
    system("pause");
    return 0;
} 

g++ -S 1.cpp 生成了1.s

分析1.s

.file    "1.cpp"
.lcomm __ZStL8__ioinit, 1, 1
.def    ___main;.scl    2;.type    32;.endef
.section.rdata, "dr"
LC2:
.ascii "hello....\0"
LC3 :
    .ascii "pause\0"
    .text
    .globl    _main
    .def    _main;.scl    2;.type    32;.endef
_main :
pushl    %ebp
movl    %esp, %ebp
andl    $ - 16, %esp
subl    $32, %esp
call    ___main
movl    $1, 28(%esp)
movl    $2, 24(%esp)
leal    24(%esp), %eax
movl    %eax, 4(%esp)
leal    28(%esp), %eax
movl    %eax, (%esp)
call    __Z5swap2IiEvRT_S1_  //24-49
movl    $0x3f800000, %eax
movl    %eax, 20(%esp)
movl    $0x40000000, %eax
movl    %eax, 16(%esp)
leal    16(%esp), %eax
movl    %eax, 4(%esp)
leal    20(%esp), %eax
movl    %eax, (%esp)
call    __Z5swap2IfEvRT_S1_ //33-69
movl    $LC2, 4(%esp)
movl    $__ZSt4cout, (%esp)
call    __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
movl    $__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, 4(%esp)
movl    %eax, (%esp)
call    __ZNSolsEPFRSoS_E
movl    $LC3, (%esp)
call    _system
movl    $0, %eax
leave
ret
.section.text$_Z5swap2IiEvRT_S1_, "x"
.linkonce discard
.globl    __Z5swap2IiEvRT_S1_
.def    __Z5swap2IiEvRT_S1_;.scl    2;.type    32;.endef
__Z5swap2IiEvRT_S1_ :
pushl    %ebp
movl    %esp, %ebp
subl    $16, %esp
movl    8(%ebp), %eax
movl(%eax), %eax
movl    %eax, -4(%ebp)
movl    12(%ebp), %eax
movl(%eax), %edx
movl    8(%ebp), %eax
movl    %edx, (%eax)
movl    12(%ebp), %eax
movl - 4(%ebp), %edx
movl    %edx, (%eax)
leave
ret
.section.text$_Z5swap2IfEvRT_S1_, "x"
.linkonce discard
.globl    __Z5swap2IfEvRT_S1_
.def    __Z5swap2IfEvRT_S1_;.scl    2;.type    32;.endef
__Z5swap2IfEvRT_S1_ :
pushl    %ebp
movl    %esp, %ebp
subl    $16, %esp
movl    8(%ebp), %eax
movl(%eax), %eax
movl    %eax, -4(%ebp)
movl    12(%ebp), %eax
movl(%eax), %edx
movl    8(%ebp), %eax
movl    %edx, (%eax)
movl    12(%ebp), %eax
movl - 4(%ebp), %edx
movl    %edx, (%eax)
leave
ret
.text
.def    ___tcf_0;.scl    3;.type    32;.endef
___tcf_0 :
pushl    %ebp
movl    %esp, %ebp
subl    $24, %esp
movl    $__ZStL8__ioinit, (%esp)
call    __ZNSt8ios_base4InitD1Ev
leave
ret
.def    __Z41__static_initialization_and_destruction_0ii;.scl    3;.type    32;.endef
__Z41__static_initialization_and_destruction_0ii :
pushl    %ebp
movl    %esp, %ebp
subl    $24, %esp
cmpl    $1, 8(%ebp)
jne    L5
cmpl    $65535, 12(%ebp)
jne    L5
movl    $__ZStL8__ioinit, (%esp)
call    __ZNSt8ios_base4InitC1Ev
movl    $___tcf_0, (%esp)
call    _atexit
L5 :
leave
ret
.def    __GLOBAL__sub_I_main;.scl    3;.type    32;.endef
__GLOBAL__sub_I_main :
pushl    %ebp
movl    %esp, %ebp
subl    $24, %esp
movl    $65535, 4(%esp)
movl    $1, (%esp)
call    __Z41__static_initialization_and_destruction_0ii
leave
ret
.section.ctors, "w"
.align 4
.long    __GLOBAL__sub_I_main
.def    __ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_;.scl    2;.type    32;.endef
.def    __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc;.scl    2;.type    32;.endef
.def    __ZNSolsEPFRSoS_E;.scl    2;.type    32;.endef
.def    _system;.scl    2;.type    32;.endef
.def    __ZNSt8ios_base4InitD1Ev;.scl    2;.type    32;.endef
.def    __ZNSt8ios_base4InitC1Ev;.scl    2;.type    32;.endef
.def    _atexit;.scl    2;.type    32;.endef

5.类模板基础

#include <iostream>
using namespace std;

//定义一个类模板
template<typename T>
class AA
{
public:
	AA(T a)
	{
		this->a = a;
	}
	void setA(T a)
	{
		this->a = a;
	}
	T getA()
	{
		return this->a
	}
protected:
private:
	T a;
};

class BB : public AA<int>
{
public:
	//BB(int a, int b) : AA(a)
	BB(int a, int b) : AA<int>(a)
	{
		this->b = b;
	}
private:
	int b;
};

void main()
{
	//要把类模板具体成类型后,才能定义变量
	AA <int> a(10);

	BB b1(1, 2);
	system("pause");
}

6.类模板遇上友元函数

#include <iostream>
using namespace std;

template<class T>
class Complex
{
public:
	Complex(T r = 0, T i = 0);
	Complex(T a) { Real = a;  Image = 0; }
	void print() const;
	//直接在类的内部声明定义,否则编译器报警
	friend Complex<T>operator+(Complex<T>&c1, Complex<T>&c2)
	{
		T r = c1.Real + c2.Real;     T i = c1.Image + c2.Image;
		return Complex<T>(r, i);
	}
	//friend Complex operator- ( const Complex<T> & c1, const Complex<T> & c2 );
	//friend Complex operator- ( const Complex<T> & c );
private:
	T  Real, Image;
};

template<class T>
Complex<T>::Complex(T r, T i)
{
	Real = r;  Image = i;
}

/*
"class Complex<int> __cdecl operator+(class Complex<int> &,class Complex<int> &)" ([email protected][email protected]@@[email protected]@Z),该符号在函数 _main 中被引用
1>E:\01-work\09-就业班0415\day16\泛型编程\Debug\泛型编程.exe : fatal error LNK1120: 1 个无法解析的外部命令
========== 生成: 成功 0 个,失败 1 个,最新 0 个,跳过 0 个 ==========
*/

// template<class T>
// Complex<T>operator+(Complex<T>&c1,Complex<T>&c2)
// {
// 	T r = c1.Real + c2.Real ;     T i = c1.Image+c2.Image ;
// 	return Complex<T>( r, i ) ;
// }

template<typename T>
void Complex<T>::print()const
{
	cout << '(' << Real << " , " << Image << ')' << endl;
}

void main()
{
	Complex<int>c1(1, 2);
	Complex<int>c2(3, 4);

	Complex<int>c3 = c1 + c2;
	c3.print();

	system("pause");
}

7.类模板遇上static

#include "iostream"
using namespace std;

const double pi = 3.14159;
template<typename T>
class Circle
{
	T radius;
	static int total;			//类模板的静态数据成员
public:
	Circle(T r = 0) { radius = r; total++; }
	void Set_Radius(T r) { radius = r; }
	double Get_Radius()   { return  radius; }
	double Get_Girth()      { return  2 * pi * radius; }
	double Get_Area()       { return  pi * radius * radius; }
	static int ShowTotal();		//类模板的静态成员函数
};

template<typename T>
int Circle<T>::total = 0;
template<typename T>
int Circle<T>::ShowTotal()
{
	return total;
}

void main()
{
	Circle<int> A, B;		//建立了2个对象
	A.Set_Radius(16);
	cout << "A.Radius = " << A.Get_Radius() << endl;
	cout << "A.Girth = " << A.Get_Girth() << endl;
	cout << "A.Area = " << A.Get_Area() << endl;
	B.Set_Radius(105);
	cout << "B.radius = " << B.Get_Radius() << endl;
	cout << "B.Girth=" << B.Get_Girth() << endl;
	cout << "B.Area = " << B.Get_Area() << endl;
	cout << "Total1=" << Circle<int>::ShowTotal() << endl;	//显示建立的对象数
	cout << endl;
	Circle<double> X(6.23), Y(10.5), Z(25.6);		//建立了3个对象
	cout << "X.Radius = " << X.Get_Radius() << endl;
	cout << "X.Girth = " << X.Get_Girth() << endl;
	cout << "X.Area = " << X.Get_Area() << endl;
	cout << "Y.radius = " << Y.Get_Radius() << endl;
	cout << "Y.Girth=" << Y.Get_Girth() << endl;
	cout << "Y.Area = " << Y.Get_Area() << endl;
	cout << "Z.Girth=" << Z.Get_Girth() << endl;
	cout << "Z.Area = " << Z.Get_Area() << endl;
	cout << "Total2=" << Circle<double>::ShowTotal() << endl;	//显示建立的对象数

	system("pause");
}
时间: 2024-10-17 14:51:19

【C/C++学院】(11)泛型编程/函数模板/类模板的相关文章

C++提高1 【泛型编程】函数模板 类模板

[本文谢绝转载] [泛型编程] 函数模板 为什么会有函数模板 现象: 函数的业务逻辑一样 函数的参数类型不一样 [最常用]函数模板  显式的调用 [不常用]类型推导 多个参数,参数定义了必须要用 函数模板,实现int类型数组,char字符串排序: 函数模板 与 普通函数的本质区别 函数模板 和 普通函数在一起 的调用型研究: C++是如何支持函数模板机制的? 函数模板机制结论 类模板 类模板的定义 类模板做函数的参数 类模板的派生成普通类 模板类的派生成模板类 复数类,所有函数都写在类的内部,运

类模板,多种类型的类模板,自定义类模板,类模板的默认类型,数组的模板实现,友元和类模板,友元函数,类模板与静态变量,类模板与普通类之间互相继承,类模板作为模板参数,类嵌套,类模板嵌套,类包装器

 1.第一个最简单的类模板案例 #include "mainwindow.h" #include <QApplication> #include <QPushButton> #include <QLabel> template<class T> class run { public: T w; void show() { w.show(); } void settext() { w.setText("A"); }

函数模板 类模板

摘要:学习函数模板的定义,使用:学习类模板的定义和使用. 函数模板: template <typename 类型参数> 返回类型 函数名(模板形参表) { 函数体 } 特点:1.函数模板可以重载(比如形参数量不同的情况). 2.定义的时候,template <typename 类型参数>到下面一个语句之间不允许插入其他语句! 3.如果程序中有和函数模板名称相同的非函数模板函数,则优先调用它. 例子: #include<iostream> using namespace

C++ - 模板类模板成员函数(member function template)隐式处理(implicit)变化

模板类模板成员函数(member function template)隐式处理(implicit)变化 本文地址: http://blog.csdn.net/caroline_wendy/article/details/24233693 指针支持隐式转换(implicit conversion), 在动态绑定中,派生类指针能够转换为基类指针. 可是模板的实例化(instantiations)之间, 是单独存在的, 派生类的实例化的模板(SmartPtr<Derived>), 不能转换为基类实例

3.2 STL中的函数对象类模板

*: STL中有一些函数对象类模板,如下所示: 1)例如要求两个double类型的x 和y 的积,可以: multiplies<double>()(x,y); 该表达式的值就是x*y的值. 2)less是STL中最常用的函数对象类模板,其定义如下: template<class _Tp> struct less { bool oprator()(const _Tp&_x,const _Tp&_y)const { return _c<_y; } } 要判断两个i

泛函编程—模板函数_类模板

函数业务逻辑一样,只是函数参数类型不同函数模板的本质:类型参数化——泛型编程 语法: template <typename T> template <class T1,class T2>多个参数类型 类型 函数名(形式参数表) { 语句序列: } 函数模板基础: template是告诉C++编译器,开始泛型编程,看到T,不要随便报错 template <typename T>//一个模板 void myswap(T& a, T& b) { T c; c

函数、类模板

泛型程序设计 算法实现时不指定具体要操作的数据的类型.适用于多种数据结构. 函数模板 Template <class 类型参数1,class类型参数2,…..> 返回值类型 模板名(形参表) { 函数体: } 函数模板可以重载,只要它们的形参表不同即可. C++编译器遵循以下优先顺序: 先找参数完全匹配的普通函数(非由模板实例化而得的函数) 再找参数完全匹配的模板函数 再找实参经过自动类型转换后能匹配的普通函数 上面的都不符合则报错. 可以在函数模板中使用多个类型参数,可以避免二义性. #in

函数模板&amp;类模板

1.函数模板 关键字template总是放在模板的定义与声明的最前面.关键字后面是用逗号分隔的模板参数表,它用尖括号(<>)括起来.该列表是模板参数表,不能为空.模板参数分为:(1) 模板类型参数,代表一种类型:(2) 模板非类型参数,代表一个常量表达式. eg:        template <class Type>        Type min(Type a,Type b)        {              return a<b ? a : b;      

C++笔记(7):泛型编程和模板(函数模板和类模板)

泛型编程和模板 0.泛型编程 1.函数模板 2.类模板 ----------------------------------------------------------------------------------------------------------- 0.泛型编程 所谓泛型就是以独立于任何特定类型的方式编写代码.前面介绍的标准库的容器.迭代器和算法都是泛型编程的具体应用. 模板是泛型编程的基础.使用模板的时候不需要知道模板是如何定义的,但今天我们来介绍如何定义自己的模板类和模