【本文谢绝转载】
【泛型编程】
函数模板
为什么会有函数模板
现象:
函数的业务逻辑一样
函数的参数类型不一样
【最常用】函数模板 显式的调用
【不常用】类型推导
多个参数,参数定义了必须要用
函数模板,实现int类型数组,char字符串排序:
函数模板 与 普通函数的本质区别
函数模板 和 普通函数在一起 的调用型研究:
C++是如何支持函数模板机制的?
函数模板机制结论
类模板
类模板的定义
类模板做函数的参数
类模板的派生成普通类
模板类的派生成模板类
复数类,所有函数都写在类的内部,运算符重载热身
复数类,所有函数都写在类的内部, 类模板
【演示】滥用友元函数的后果--正常的代码准备
复数类,所有函数都写在类的内部(一个CPP中):问题抛出
当模板函数遇到友元函数,问题解决:
滥用友元函数的后果
【结论】:不需要友元函数,不要用友元函数
【结论】模板类的cpp文件 与 .h头文件分开写的时候,要把cpp文件也包含进来
当类模板中有static成员变量时;从类模板的实质分析,编译器你会自动为我们写成两个类
类模板 数组案例
类模板 结构体案例
作业:
-------------------------------------------------------------------------
【为什么会有函数模板】
chunli@http://990487026.blog.51cto.com~/c++$ cat main.cpp
#include
using namespace std;
void swap1(int &a,int &b)
{
a = a ^ b;
b = a ^ b;
a = a ^ b;
}
void swap2(char &a,char &b)
{
a = a ^ b;
b = a ^ b;
a = a ^ b;
}
int main()
{
int a = 10;
int b = 20;
swap1(a,b);
cout <
现象:
函数的业务逻辑一样
函数的参数类型不一样
【最常用】函数模板 显式的调用
chunli@http://990487026.blog.51cto.com~/c++$ cat main.cpp
#include
using namespace std;
//template //告诉编译器,我要开始泛型编程了
template
void myswap(T &a,T &b)
{
a = a ^ b;
b = a ^ b;
a = a ^ b;
}
int main()
{
int a = 10;
int b = 20;
cout <(a,b);
cout <(c,d);
cout <
【不常用】类型推导
chunli@http://990487026.blog.51cto.com~/c++$ cat main.cpp
#include
using namespace std;
//template //告诉编译器,我要开始泛型编程了
template
void myswap(T &a,T &b)
{
a = a ^ b;
b = a ^ b;
a = a ^ b;
}
int main()
{
int a = 10;
int b = 20;
cout <
多个参数,参数定义了必须要用
chunli@http://990487026.blog.51cto.com~/c++$ cat main.cpp
#include
using namespace std;
//template //告诉编译器,我要开始泛型编程了
template
void myswap(T &a,T &b,str s)
{
a = a ^ b;
b = a ^ b;
a = a ^ b;
cout << s << endl;
}
int main()
{
int a = 10;
int b = 20;
cout <
函数模板,实现int类型数组,char字符串排序:
chunli@http://990487026.blog.51cto.com~/c++$ cat main.cpp
#include
#include
#include
using namespace std;
template
void select_sort(T1 array[],T2 len)
{
if(array == NULL)
{
return ;
}
for(int i=0;i array[j])
{
min = j ;
}
}
int tmp = array[i];
array[i] = array[min];
array[min]= tmp;
}
}
template
void print_arr(T1 array[],T2 len)
{
if(array == NULL)
{
return ;
}
for(int i=0;i(arr,n);
print_arr(arr,n);
char str[]= "Hello,Linux!";
int m = strlen(str);
select_sort(str,m);
print_arr(str,m);
return 0;
}
chunli@http://990487026.blog.51cto.com~/c++$ g++ -g -o run main.cpp && ./run
0 1 2 3 4 5 6 7 8 9
! , H L e i l l n o u x
chunli@http://990487026.blog.51cto.com~/c++$
函数模板 与 普通函数的本质区别
chunli@http://990487026.blog.51cto.com~/c++$ cat main.cpp
#include
#include
#include
using namespace std;
//swap 在 C++是个库函数
template
void my_swap(T &a,T &b)
{
cout <
函数模板 和 普通函数在一起 的调用型研究:
【补充】在同一作用域,可以发生函数重载
chunli@http://990487026.blog.51cto.com~/c++$ cat main.cpp
/*
1 函数模板可以像普通函数一样被重载
2 C++编译器优先考虑普通函数
3 如果函数模板可以产生一个更好的匹配,那么选择模板
4 可以通过空模板实参列表的语言限定编译器只通过模板匹配
*/
#include
#include
#include
using namespace std;
template
T Max(T a,T b) //不要引用类型
{
cout <b?a:b;
}
template
T Max(T a,T b,T c)
{
cout <b?a:b;
}
int main()
{
int a = 1;
int b = 2;
Max(a,b); //C++编译器优先考虑普通函数
Max<>(a,b); //可以通过空模板实参列表的语言限定编译器只通过模板匹配
Max(3.5,4.4); //优先选择模板函数,因为模板函数能产生更好的匹配
Max(3.5,4.4,6.8);//只有函数模板能匹配
Max('A',66); //普通函数可以进行隐式转换
return 0;
}
chunli@http://990487026.blog.51cto.com~/c++$ g++ -g -o run main.cpp && ./run
1 2 我是普通函数
1 2 我是2号函数模板
3.5 4.4 我是2号函数模板
3.5 4.4 我是3号函数模板,会调用两次max函数
3.5 4.4 我是2号函数模板
4.4 6.8 我是2号函数模板
65 66 我是普通函数
chunli@http://990487026.blog.51cto.com~/c++$
C++是如何支持函数模板机制的?
C++:
#include
#include
#include
using namespace std;
//swap 在 C++是个库函数
template
void my_swap(T &a,T &b)
{
T c = 0;
c = a;
a = b;
b = c;
cout <(a,b);
char c = 'C';
char d = 'D';
my_swap(c,d);
return 0;
}
编译成汇编:
.file "main.c"
.lcomm __ZStL8__ioinit,1,1
.def ___main; .scl 2; .type 32; .endef
.text
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
LFB1025:
.cfi_startproc
.cfi_personality 0,___gxx_personality_v0
.cfi_lsda 0,LLSDA1025
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
andl $-16, %esp
subl $32, %esp
call ___main
movl $69, 28(%esp)
movl $20, 24(%esp)
leal 24(%esp), %eax
movl %eax, 4(%esp)
leal 28(%esp), %eax
movl %eax, (%esp)
LEHB0:
call __Z7my_swapIiEvRT_S1_
movb $67, 23(%esp)
movb $68, 22(%esp)
leal 22(%esp), %eax
movl %eax, 4(%esp)
leal 23(%esp), %eax
movl %eax, (%esp)
call __Z7my_swapIcEvRT_S1_
LEHE0:
movl $0, %eax
jmp L5
L4:
movl %eax, (%esp)
LEHB1:
call __Unwind_Resume
LEHE1:
L5:
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
LFE1025:
.def ___gxx_personality_v0; .scl 2; .type 32; .endef
.section .gcc_except_table,"w"
LLSDA1025:
.byte 0xff
.byte 0xff
.byte 0x1
.uleb128 LLSDACSE1025-LLSDACSB1025
LLSDACSB1025:
.uleb128 LEHB0-LFB1025
.uleb128 LEHE0-LEHB0
.uleb128 L4-LFB1025
.uleb128 0
.uleb128 LEHB1-LFB1025
.uleb128 LEHE1-LEHB1
.uleb128 0
.uleb128 0
LLSDACSE1025:
.text
.section .rdata,"dr"
LC0:
.ascii " \0"
LC1:
.ascii " \316\322\312\307\272\257\312\375\304\243\260\345\12\0"
.section .text$_Z7my_swapIiEvRT_S1_,"x"
.linkonce discard
.globl __Z7my_swapIiEvRT_S1_
.def __Z7my_swapIiEvRT_S1_; .scl 2; .type 32; .endef
__Z7my_swapIiEvRT_S1_:
LFB1026:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
pushl %ebx
subl $36, %esp
.cfi_offset 3, -12
movl $0, -12(%ebp)
movl 8(%ebp), %eax
movl (%eax), %eax
movl %eax, -12(%ebp)
movl 12(%ebp), %eax
movl (%eax), %edx
movl 8(%ebp), %eax
movl %edx, (%eax)
movl 12(%ebp), %eax
movl -12(%ebp), %edx
movl %edx, (%eax)
movl 12(%ebp), %eax
movl (%eax), %ebx
movl 8(%ebp), %eax
movl (%eax), %eax
movl %eax, (%esp)
movl $__ZSt4cout, %ecx
call __ZNSolsEi
subl $4, %esp
movl $LC0, 4(%esp)
movl %eax, (%esp)
call __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
movl %ebx, (%esp)
movl %eax, %ecx
call __ZNSolsEi
subl $4, %esp
movl $LC1, 4(%esp)
movl %eax, (%esp)
call __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
movl -4(%ebp), %ebx
leave
.cfi_restore 5
.cfi_restore 3
.cfi_def_cfa 4, 4
ret
.cfi_endproc
LFE1026:
.section .text$_Z7my_swapIcEvRT_S1_,"x"
.linkonce discard
.globl __Z7my_swapIcEvRT_S1_
.def __Z7my_swapIcEvRT_S1_; .scl 2; .type 32; .endef
__Z7my_swapIcEvRT_S1_:
LFB1027:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
pushl %ebx
subl $36, %esp
.cfi_offset 3, -12
movb $0, -9(%ebp)
movl 8(%ebp), %eax
movzbl (%eax), %eax
movb %al, -9(%ebp)
movl 12(%ebp), %eax
movzbl (%eax), %edx
movl 8(%ebp), %eax
movb %dl, (%eax)
movl 12(%ebp), %eax
movzbl -9(%ebp), %edx
movb %dl, (%eax)
movl 12(%ebp), %eax
movzbl (%eax), %eax
movsbl %al, %ebx
movl 8(%ebp), %eax
movzbl (%eax), %eax
movsbl %al, %eax
movl %eax, 4(%esp)
movl $__ZSt4cout, (%esp)
call __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_c
movl $LC0, 4(%esp)
movl %eax, (%esp)
call __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
movl %ebx, 4(%esp)
movl %eax, (%esp)
call __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_c
movl $LC1, 4(%esp)
movl %eax, (%esp)
call __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
addl $36, %esp
popl %ebx
.cfi_restore 3
popl %ebp
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
LFE1027:
.text
.def ___tcf_0; .scl 3; .type 32; .endef
___tcf_0:
LFB1033:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
subl $8, %esp
movl $__ZStL8__ioinit, %ecx
call __ZNSt8ios_base4InitD1Ev
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
LFE1033:
.def __Z41__static_initialization_and_destruction_0ii; .scl 3; .type 32; .endef
__Z41__static_initialization_and_destruction_0ii:
LFB1032:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
subl $24, %esp
cmpl $1, 8(%ebp)
jne L9
cmpl $65535, 12(%ebp)
jne L9
movl $__ZStL8__ioinit, %ecx
call __ZNSt8ios_base4InitC1Ev
movl $___tcf_0, (%esp)
call _atexit
L9:
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
LFE1032:
.def __GLOBAL__sub_I_main; .scl 3; .type 32; .endef
__GLOBAL__sub_I_main:
LFB1034:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
subl $24, %esp
movl $65535, 4(%esp)
movl $1, (%esp)
call __Z41__static_initialization_and_destruction_0ii
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
LFE1034:
.section .ctors,"w"
.align 4
.long __GLOBAL__sub_I_main
.ident "GCC: (rev2, Built by MinGW-builds project) 4.8.0"
.def __Unwind_Resume; .scl 2; .type 32; .endef
.def __ZNSolsEi; .scl 2; .type 32; .endef
.def __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc; .scl 2; .type 32; .endef
.def __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_c; .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
类模板:
类模板用于实现类所需数据的类型参数化
类模板在表示如数组、表、图等数据结构显得特别重要,
类模板的定义
类末班的使用
chunli@http://990487026.blog.51cto.com~/c++$ cat main.cpp
#include
#include
#include
using namespace std;
template
class A
{
public:
A(T a)
{
this->a = a;
}
void printf()
{
cout << "a= "<a(11); //模板类是抽象类 必须指定具体的类型,告诉编译器给我分配多少内存
a.printf();
return 0;
}
chunli@http://990487026.blog.51cto.com~/c++$ g++ -g -o run main.cpp && ./run
a= 11
chunli@http://990487026.blog.51cto.com~/c++$
类模板做函数的参数
chunli@http://990487026.blog.51cto.com~/c++$ cat main.cpp
#include
#include
#include
using namespace std;
template
class A
{
public:
A(T a)
{
this->a = a;
}
void printf()
{
cout << "a= "< &a)//这里如果来个变量,会进行拷贝构造,引用就不会
{
a.printf();
}
int main()
{
A a(11); //定义一个变量
A b(22),c(33);
useA(a); //来模板做函数的参数
useA(b);
useA(c);
return 0;
}
chunli@http://990487026.blog.51cto.com~/c++$ g++ -g -o run main.cpp && ./run
a= 11
a= 22
a= 33
chunli@http://990487026.blog.51cto.com~/c++$
类模板的派生成普通类
chunli@http://990487026.blog.51cto.com~/c++$ cat main.cpp
#include
#include
#include
using namespace std;
template
class A
{
public:
A(T a)
{
this->a = a;
}
void printf()
{
cout << "a= "<
{
public:
B(int a,int b):A(a)
{
this->b = b;
}
void printf()
{
cout << "a="<
模板类的派生成模板类
chunli@http://990487026.blog.51cto.com~/c++$ cat main.cpp
#include
#include
#include
using namespace std;
template
class A
{
public:
A(T a)
{
this->a = a;
}
void printf()
{
cout << "a= "<
class C:public A
{
public:
C(T c,T a):A(a)
{
this->c = a;
}
void printf()
{
cout << "c=" << c<< endl;
}
private:
T c;
};
int main()
{
C c1(1,2); c1.printf();
C c2(66,65); c2.printf();
return 0;
}
chunli@http://990487026.blog.51cto.com~/c++$ g++ -g -o run main.cpp && ./run
c=2
c=A
chunli@http://990487026.blog.51cto.com~/c++$
复数类,所有函数都写在类的内部,运算符重载热身
chunli@http://990487026.blog.51cto.com~/c++$ cat main.cpp
#include
#include
#include
using namespace std;
class Complex
{
friend ostream& operator<<(ostream &out,Complex &c);
public:
Complex(int a = 0,int b = 0)
{
this->a = a;
this->b = b;
}
void printf()
{
cout << "a= "<a=" << this->a << " c2.a="<b=" << this->b << " c2.b="<a + c2.a,this->b+c2.b);
return tmp;
}
protected:
int a;
int b;
};
//为输出类的信息,实现操作符重载
ostream& operator<<(ostream &out,Complex &c)
{
cout <<"a="<
复数类,所有函数都写在类的内部, 类模板
chunli@http://990487026.blog.51cto.com~/c++$ cat main.cpp
#include
#include
#include
using namespace std;
/*
运算符重载的正规写法
重载<< >> 只能用友元函数,其他操作符都要写成成员函数,不要滥用友元函数
*/
template
class Complex
{
//为输出类的信息,实现操作符重载
friend ostream& operator<<(ostream &out,Complex &c)
{
cout << "进入<<操作符重载 -> ";
out <<"a="<a = a;
this->b = b;
}
void printf()
{
cout << "a= "<a=" << this->a << " c2.a="<b=" << this->b << " c2.b="<a + c2.a,this->b+c2.b);
return tmp;
}
protected:
T a;
T b;
};
/*
ostream& operator<<(ostream &out,Complex &c)
{
cout <<"a="< c1(2,4);
Complex c2(3,5);
Complex c3 = c1 +c2; c3.printf();
cout << c3 << endl; //在得不到cout的源代码下,只能使用友元函数
return 0;
}
chunli@http://990487026.blog.51cto.com~/c++$ g++ -g -o run main.cpp && ./run
a= 5 b=9
进入<<操作符重载 -> a=5 b=9
chunli@http://990487026.blog.51cto.com~/c++$
【演示】滥用友元函数的后果--正常的代码准备
chunli@http://990487026.blog.51cto.com~/c++$ cat main.cpp
#include
#include
#include
using namespace std;
/*
运算符重载的正规写法
重载<< >> 只能用友元函数,其他操作符都要写成成员函数,不要滥用友元函数
*/
template
class Complex
{
//为输出类的信息,实现操作符重载
friend ostream& operator<<(ostream &out,Complex &c)
{
cout << "进入<<操作符重载 -> ";
out <<"a="<a = a;
this->b = b;
}
void printf()
{
cout << "a= "<a=" << this->a << " c2.a="<b=" << this->b << " c2.b="<a + c2.a,this->b+c2.b);
return tmp;
}
protected:
T a;
T b;
};
/*
ostream& operator<<(ostream &out,Complex &c)
{
cout <<"a="< c1(2,4);
Complex c2(3,5);
Complex c4 = MySub(c1,c2);
cout << c4 << endl;
return 0;
}
chunli@http://990487026.blog.51cto.com~/c++$ g++ -g -o run main.cpp && ./run
进入MySub 函数
进入<<操作符重载 -> a=-1 b=-1
chunli@http://990487026.blog.51cto.com~/c++$
复数类,所有函数都写在类的内部(一个CPP中):问题抛出
chunli@http://990487026.blog.51cto.com~/c++$ cat main.cpp
#include
#include
#include
using namespace std;
template
class Complex
{
//为输出类的信息,实现操作符重载
friend ostream& operator<<(ostream &out,Complex &c);
friend Complex MySub(Complex& c1,Complex&c2)
{
cout << "进入MySub 函数 \n";
Complex tmp(c1.a - c2.a,c1.b - c2.b);
return tmp;
}
public:
Complex (T a ,T b);
void printf();
Complex operator+(Complex &c2);
protected:
T a;
T b;
};
/*
问题的本质是:模板是两次编译,
第一次生成的函数头 和第二次生成的不一样
*/
template
ostream& operator<<(ostream &out,Complex &c)
{
out <<"a="<
//函数的返回的类型要具体化
//函数的实参也要具体化
Complex Complex:: operator+(Complex &c2)
{
cout << "进入外部 operator+ \n";
//Complex tmp(this->a + c2.a,this->b+c2.b);
Complex tmp(this->a + c2.a,this->b+c2.b);
return tmp;
}
template
Complex::Complex (T a ,T b)
{
cout << "进入外部Complex函数 a=" <a = a;
this->b = b;
}
template
void Complex::printf()
{
cout << "进入外部printf函数 ";
cout << "a="< c1(2,4); c1.printf();
Complex c2(3,5);
Complex c3 = c1 + c2;
Complex c4 = MySub(c1,c2);
cout << c4 << endl;
return 0;
}
chunli@http://990487026.blog.51cto.com~/c++$ g++ -g -o run main.cpp && ./run
main.cpp:10:52: warning: friend declaration ‘std::ostream& operator<<(std::ostream&, Complex&)’ declares a non-template function [-Wnon-template-friend]
friend ostream& operator<<(ostream &out,Complex &c);
chunli@http://990487026.blog.51cto.com~/c++$
当模板函数遇到友元函数,问题解决:
chunli@http://990487026.blog.51cto.com~/c++$ cat haha.cpp
#include
using namespace std;
template
class Complex
{
friend std::ostream& operator << (std::ostream& os, const Complex& c);
public:
Complex(T a, T b);
protected:
T a;
T b;
};
template
std::ostream& operator <<(std::ostream& os, const Complex& c)
{
os << "a="<
Complex::Complex(T a, T b)
{
cout << "进入外部Complex函数 a=" << a << " b=" << b << endl;;
this->a = a;
this->b = b;
}
int main()
{
Complex c1(2, 4);
cout << c1 << endl;
return 0;
}
VS下编译,通过:
C:\Users\chunli\Documents\c_c++\ConsoleApplication2\Debug>ConsoleApplication2.exe
进入外部Complex函数 a=2 b=4
a=2 b= 4
Linux GCC 编译 不通过:
chunli@http://990487026.blog.51cto.com~/c++$ g++ -g -o run haha.cpp && ./run
haha.cpp: In instantiation of ‘class Complex’:
haha.cpp:33:17: required from here
haha.cpp:7:23: error: template-id ‘operator<< ’ for ‘std::ostream& operator<<(std::ostream&, const Complex&)’ does not match any template declaration
friend std::ostream& operator << (std::ostream& os, const Complex& c);
^
chunli@http://990487026.blog.51cto.com~/c++$
滥用友元函数的后果
#include
using namespace std;
template
class Complex;
template
Complex MySub(Complex &c1, Complex &c2);
template
class Complex
{
friend std::ostream& operator << (std::ostream& os, const Complex& c);
friend Complex MySub(Complex &c1, Complex &c2);
public:
Complex(T a, T b);
protected:
T a;
T b;
};
template
Complex MySub(Complex &c1, Complex &c2)
{
Complex tmp(c1.a - c2.a, c1.b - c2.b);
return tmp;
}
template
std::ostream& operator <<(std::ostream& os, const Complex& c)
{
os << "a="<
Complex::Complex(T a, T b)
{
cout << "进入外部Complex函数 a=" << a << " b=" << b << endl;;
this->a = a;
this->b = b;
}
int main()
{
Complex c1(2, 4);
Complex c2(1, 2);
Complex c3 = MySub(c1,c2);
cout << c3 << endl;
return 0;
}
Linux GCC编译不通过
VS 编译OK
C:\Users\chunli\Documents\c_c++\ConsoleApplication2\Debug>ConsoleApplication2.exe
进入外部Complex函数 a=2 b=4
进入外部Complex函数 a=1 b=2
进入外部Complex函数 a=1 b=2
a=1 b= 2
【结论】:不需要友元函数,不要用友元函数
【结论】模板类的cpp文件 与 .h头文件分开写的时候,要把cpp文件也包含进来
当类模板中有static成员变量时;
从类模板的实质分析,编译器你会自动为我们写成两个类
chunli@http://990487026.blog.51cto.com~/c++$ cat main.cpp
#include
using namespace std;
template
class A
{
public:
static T a;
};
template
T A::a = 0;
int main()
{
A a1; a1.a++;
A a2; a2.a++;
A a3; a3.a++;
cout << "a3="< b1; b1.a += 3.5;
A b2; b2.a += 3.5;
A b3; b3.a += 3.5;
cout << "b3="<
类模板 数组案例
1主函数:
#define _CRT_SECURE_NO_WARNINGS
#include
using namespace std;
#include "MyVector.cpp"
void main()
{
MyVector myv1(10);
for (int i = 0; i myv2 = myv1;
for (int i = 0; i
2头文件:MyVector
#include
using namespace std;
template
class MyVector
{
friend ostream & operator<< (ostream &out, const MyVector &obj);
public:
MyVector(int size = 0); //构造函数
MyVector(const MyVector &obj); // 拷贝构造函数
~MyVector(); //析构函数
public:
T& operator[] (int index);
// a3 = a2 = a1;
MyVector &operator=(const MyVector &obj);
public:
int getLen()
{
return m_len;
}
protected:
T *m_space;
int m_len;
};
类函数实现文件 MyVector.cpp
#include
using namespace std;
#include "MyVector.h"
template
ostream & operator<<(ostream &out, const MyVector &obj)
{
for (int i = 0; i myv1(10);
template
MyVector::MyVector(int size) //构造函数
{
m_space = new T[size];
m_len = size;
}
//MyVector myv2 = myv1;
template
MyVector::MyVector(const MyVector &obj) // 拷贝构造函数
{
//根据myv1的大小分配内存
m_len = obj.m_len;
m_space = new T[m_len];
//copy数据
for (int i = 0; i
MyVector::~MyVector() //析构函数
{
if (m_space != NULL)
{
delete[] m_space;
m_space = NULL;
m_len = 0;
}
}
template
T& MyVector::operator[] (int index)
{
return m_space[index];
}
// a3 = a2 = a1;
template
MyVector & MyVector::operator=(const MyVector &obj)
{
//先把a2的旧的内存释放掉
if (m_space != NULL)
{
delete[] m_space;
m_space = NULL;
m_len = 0;
}
//根据a1分配内存
m_len = obj.m_len;
m_space = new T[m_len];
//copy数据
for (int i = 0; i
VS环境编译运行:
C:\Users\chunli\Documents\c_c++\ConsoleApplication2\Debug>ConsoleApplication2.exe
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10
hello...
请按任意键继续. . .
类模板 结构体案例
类函数实现文件 MyVector.h 内容不变
类函数实现文件 MyVector.cpp内容不变
主函数修改为:
main.cpp
#define _CRT_SECURE_NO_WARNINGS
#include
using namespace std;
#include "MyVector.cpp"
class Teacher
{
public:
Teacher()
{
age = 33;
strcpy(name, "");
}
Teacher(char *name, int age)
{
this->age = age;
strcpy(this->name, name);
}
void printT()
{
cout << name << ", " << age << endl;
}
private:
int age;
char name[32];
};
void main()
{
Teacher t1("t1", 31), t2("t2", 32), t3("t3", 33), t4("t4", 34);
MyVector tArray(4);
tArray[0] = t1;
tArray[1] = t2;
tArray[2] = t3;
tArray[3] = t4;
for (int i = 0; i<4; i++)
{
Teacher tmp = tArray[i];
tmp.printT();
}
}
VS编译运行:
C:\Users\chunli\Documents\c_c++\ConsoleApplication2\Debug>ConsoleApplication2.exe
t1, 31
t2, 32
t3, 33
t4, 34
C:\Users\chunli\Documents\c_c++\ConsoleApplication2\Debug>
作业:
在上面这个程序的基础之上:
1 优化Teacher类, 属性变成 char *panme, 购置函数里面 分配内存
2 优化Teacher类,析构函数 释放panme指向的内存空间
3 优化Teacher类,避免浅拷贝 重载= 重写拷贝构造函数
4 优化Teacher类,在Teacher增加 <<
5 在模板数组类中,存int char Teacher Teacher*(指针类型)