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

简介: <h1><span style="font-family:'Microsoft YaHei UI','Microsoft YaHei',SimSun,'Segoe UI',Tahoma,Helvetica,sans-serif,'Microsoft YaHei',Georgia,Helvetica,Arial,sans-serif,宋体,PMingLiU,serif; font-size:

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> &)" (??H@YA?AV?$Complex@H@@AAV0@0@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");
}





目录
相关文章
|
28天前
|
安全 算法 C++
【C/C++ 泛型编程 应用篇】C++ 如何通过Type traits处理弱枚举和强枚举
【C/C++ 泛型编程 应用篇】C++ 如何通过Type traits处理弱枚举和强枚举
46 3
|
7天前
|
编译器 C++
C++编程之美:探索初始化之源、静态之恒、友情之桥与匿名之韵
C++编程之美:探索初始化之源、静态之恒、友情之桥与匿名之韵
18 0
|
12天前
|
编译器 C语言 C++
【C++初阶(九)】C++模版(初阶)----函数模版与类模版
【C++初阶(九)】C++模版(初阶)----函数模版与类模版
18 0
|
23天前
|
存储 缓存 C++
C++链表常用的函数编写(增查删改)内附完整程序
C++链表常用的函数编写(增查删改)内附完整程序
|
25天前
|
存储 安全 编译器
【C++】类的六大默认成员函数及其特性(万字详解)
【C++】类的六大默认成员函数及其特性(万字详解)
35 3
|
28天前
|
安全 程序员 C++
【C++ 基本知识】现代C++内存管理:探究std::make_系列函数的力量
【C++ 基本知识】现代C++内存管理:探究std::make_系列函数的力量
101 0
|
28天前
|
设计模式 安全 C++
【C++ const 函数 的使用】C++ 中 const 成员函数与线程安全性:原理、案例与最佳实践
【C++ const 函数 的使用】C++ 中 const 成员函数与线程安全性:原理、案例与最佳实践
71 2
|
29天前
|
存储 移动开发 安全
【C/C++ 口语】C++ 编程常见接口发音一览(不断更新)
【C/C++ 口语】C++ 编程常见接口发音一览(不断更新)
22 0
|
1天前
|
设计模式 Java C++
【C++高阶(八)】单例模式&特殊类的设计
【C++高阶(八)】单例模式&特殊类的设计
|
1天前
|
编译器 C++
【C++基础(八)】类和对象(下)--初始化列表,友元,匿名对象
【C++基础(八)】类和对象(下)--初始化列表,友元,匿名对象

热门文章

最新文章