Day48、模板特化、智能指针、模板的其他特性
来源:互联网 发布:九三学社入社条件知乎 编辑:程序博客网 时间:2024/05/14 04:13
7、特(例)化
当一个类模板的通用实现无法满足某些特殊类型的需要,或者虽然可以满足其需要,但是性能不佳,这时可以编写针对该特殊类型的特殊实现,这就叫做类模板的特(例)化。
1) 完全特化:针对全部类型参数的特化。
A:全类特化:用特定类型替换类型参数,把整个类模板重写一遍
B:成员特化:只重写类模板中部分与特定类型相关的成员函数
#include <iostream>
#include <cstring>
using namespace std;
// 通用版本
template<typename T>
T max (T x, T y) {
returnx < y ? y : x;
}
// 针对字符指针类型的重载版本
char* max (char* x, char* y) {
returnstrcmp (x, y) < 0 ? y : x;
}
// 通用版本
template<typename T>
class Comparator {
public:
Comparator(T x, T y) :
m_x(x), m_y (y) {}
Tmax (void) const {
returnm_x < m_y ? m_y : m_x;
}
/*
char*max (void) const {
returnstrcmp (m_x, m_y) < 0 ?
m_y: m_x;
}
*/
private:
Tm_x, m_y;
};
// 针对字符指针类型的特化版本
/*
template<>
class Comparator<char*> {
public:
Comparator(char* x, char* y) :
m_x(x), m_y (y) {}
char*max (void) const {
returnstrcmp (m_x, m_y) < 0 ?
m_y: m_x;
}
private:
char*m_x, *m_y;
};
*/
template<>
char* Comparator<char*>::max (void)const {
returnstrcmp (m_x, m_y) < 0 ? m_y : m_x;
}
int main (void) {
inta = 123, b = 456;
cout<< ::max (a, b) << endl;
charc[] = "hello", d[] = "world";
cout<< ::max (c, d) << endl;
/*
cout<< ::max<string> (c, d) << endl;
cout<< ::max (string (c), string (d))
<<endl;
*/
Comparator<int>ci (a, b);
cout<< ci.max () << endl;
Comparator<char*>cs (c, d);
cout<< cs.max () << endl;
return0;
}
tarena@tarena-virtual-machine:~/day48/day02$./a.out
456
world
456
world
2) 局部特化:针对部分类型参数所做的特化。
举例:
#include<iostream>
using namespace std;
//通用模板
template<typename A,typename B>
class X{
public:
X(void){
cout<<"X<A,B>"<<endl;
}
private:
Am_a;
Bm_b;
};
//完全特化
template<>
class X<int,short>{
public:
X(void){
cout<<"X<int,short>"<<endl;
}
private:
int m_a;
short m_b;
};
//局部特化
template<typename A>
class X<A,short>{
public:
X(void){
cout<<"X<A,short>"<<endl;
}
private:
Am_a;
short m_b;
};
//局部特化
template<typename A>
class X<A,A>{
public:
X(void){
cout<<"X<A,A>"<<endl;
}
private:
Am_a;
Am_b;
};
//局部特化
template<typename A>
class X<A,A*>{
public:
X(void){
cout<<"X<A,A*>"<<endl;
}
private:
Am_a;
A* m_b;
};
//局部特化
template<typename A,typename B>
class X<A*,B*>{//都是指针类型
public:
X(void){
cout<<"X<A*,B*>"<<endl;
}
private:
A* m_a;
B* m_b;
};
template<typename A>
class X<A*,A*>{//都是指针类型
public:
X(void){
cout<<"X<A*,A*>"<<endl;
}
private:
A* m_a;
A* m_b;
};
int main(void){
//选择顺序:完全特化>局部特化>通用版本
X<int,short>x1;//完全特化
X<double,short>x2;//局部特化
X<char,short>x3;//局部特化
X<int,double>x4;//通用模板
X<int,int>x5;//两个类型参数一样时
X<double,double>x6;
X<double,double*>x7;//前者普通类型,后者指针
X<int*,double*>x8;//都是指针
X<short**,char*****>x9;//都是指针
X<int*,int*>x10;//同类型指针
}
8、智能指针
1)利用局部对象的析构函数销毁堆对象
2)通过操作符重载模拟普通指针的用法;
3)通过类型参数泛型化所维护的堆对象
4)通过转移语义避免浅拷贝和深拷贝的矛盾
5)通过局部特化区分单个对象和对象数组
Auto.cpp
#include <errno.h>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <memory>
using namespace std;
class A {
public:
A(void) {
cout<< "A构造:"<< this << "->"
<<sizeof (*this) << endl;
}
~A(void) {
cout<< "A析构:"<< this << "->"
<<sizeof (*this) << endl;
}
voidprint (size_t i) const {
cout<< m_data[i] << endl;
}
intm_data[1024];
};
template<typename T>
class AutoPtr {
public:
AutoPtr(T* p = NULL) : m_p (p) {}
AutoPtr(AutoPtr& that) :
m_p(that.release ()) {}
AutoPtr&operator= (AutoPtr& rhs) {
if(&rhs != this)
reset(rhs.release ());
return*this;
}
~AutoPtr(void) {
deletem_p;
}
T&operator* (void) const {
return*m_p;
}
T*operator-> (void) const {
return&**this;
}
private:
T*release (void) {
T*p = m_p;
m_p= NULL;
returnp;
}
voidreset (T* p) {
if(p != m_p) {
deletem_p;
m_p= p;
}
}
T*m_p;
};
template<typename T>
class AutoPtr<T[]> {
public:
AutoPtr(T* p = NULL) : m_p (p) {}
AutoPtr(AutoPtr& that) :
m_p(that.release ()) {}
AutoPtr&operator= (AutoPtr& rhs) {
if(&rhs != this)
reset(rhs.release ());
return*this;
}
~AutoPtr(void) {
delete[]m_p;
}
T&operator* (void) const {
return*m_p;
}
T*operator-> (void) const {
return&**this;
}
private:
T*release (void) {
T*p = m_p;
m_p= NULL;
returnp;
}
voidreset (T* p) {
if(p != m_p) {
delete[]m_p;
m_p= p;
}
}
T*m_p;
};
void foo (void) {
/*
Aa, *pa = &a;
pa->m_data[0]= 12345;
(*pa).print(0);
*/
// A*pa = new A;
AutoPtr<A>pa (new A);
pa->m_data[0]= 12345;
// pa.operator->()->m_data[0]= 12345;
(*pa).print(0);
// pa.operator*().print(0);
AutoPtr<A>pb = pa; // 拷贝构造
++pb->m_data[0];
(*pb).print(0); // 12346
AutoPtr<A>pc (new A);
pc->m_data[0]= 22222;
pb= pc; // 拷贝赋值
++pb->m_data[0];
(*pb).print(0); // 12346
FILE*fp = fopen ("none", "r");
if(! fp) {
// deletepa;
throwerrno;
}
//...
fclose(fp);
// deletepa;
}
int main (void) {
/*
try{
foo();
}
catch(int ex) {
cout<< strerror (ex) << endl;
return-1;
}
cout<< "成功!"<< endl;
*/
// AutoPtr<A[]>pa (new A[3]);
AutoPtr<A>pa (new A);
/*
auto_ptr<T>
*/
return0;
}
tarena@tarena-virtual-machine:~/day48/day02$./a.out
A构造:0x979f008->4096
A析构:0x979f008->4096
(Malloc.c New.cpp 辅助理解)
Malloc.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (void) {
char*pc = (char*)malloc (1024);
strcpy(pc, "Hello, Memory !");
printf("%p->%s, %p\n", pc, pc, pc + 512);
printf("第一次free...\n");
free(pc + 512);
printf("第二次free...\n");
free(pc);
return0;
}
已放弃 (核心已转储)
New.cpp
#include <cstdlib>
#include <iostream>
using namespace std;
class A {
public:
// ~A(void) {}
staticvoid* operator new[] (size_t size){
void*p = malloc (size);
cout<< p << "->" << size << "字节"
<<endl;
returnp;
}
staticvoid operator delete[] (void* p) {
cout<< p << endl;
free(p);
}
stringm_data;
};
int main (void) {
A*pa = new A[3];
cout<< "pa=" << pa << endl;
cout<< *((int*)pa-1) << endl;
delete[]pa;
// deletepa;
return0;
}
tarena@tarena-virtual-machine:~/day48/day02$./a.out
0x978b008->16字节
pa=0x978b00c
3
0x978b008
C++2011中一般不推荐使用auto_ptr,而是代之以smart_ptr。
三、模板的其他特性
1、缺省参数
1)类模板的模板参数可以带有缺省值,实例化该模板时,如果提供了相应的实参则忽略缺省值,反之则以缺省作为对应形参的值。
2)如果某个模板参数带有缺省值,那么它后面的所有参数必须都带有缺省值。
3)C++98不允许为函数模板的模板参数指定缺省值,但是C++11允许。
(模板参数是在编译期间作用)
GCC<4.8 : g++ default.cpp -std=c++0x
GCC>=4.8 : g++ default.cpp –std=c++11
4)对函数模板,如果模板参数的缺省值与隐式推断的类型不一致,以隐式推断的类型为准,忽略其缺省值。
举例:videfault.cpp
#include <iostream>
#include <typeinfo>
using namespace std;
/*
template<typename A = int,
typenameB = double, typename C = string>
*/
template<typename A,
typenameB = double, typename C = string>
/*
template<typename A = int,
typenameB, typename C = string>
template<typename A = int,
typenameB = double, typename C>
*/
class X {
public:
staticvoid foo (void) {
cout<< typeid (A).name () << ' '
<<typeid (B).name () << ' '
<<typeid (C).name () << endl;
}
};
int _x = 200;
void foo (int x, int y = /*x*/_x) {
cout<< x << ' ' << y << endl;
}
template<typename A, typename B = A>
//template<typename A = B, typename B =int>
class Y {
public:
staticvoid foo (void) {
cout<< typeid (A).name () << ' '
<<typeid (B).name () << endl;
}
};
template<typename A = int,
typenameB = double, typename C = string>
void fun (void) {
cout<< typeid (A).name () << ' '
<<typeid (B).name () << ' '
<<typeid (C).name () << endl;
}
template<typename T = int>
void bar (T arg) {
cout<< typeid (arg).name () << endl;
}
int main (void) {
X<char,short, long>::foo (); // c s l
X<char,short>::foo (); // c s Ss
X<char>::foo(); // c d Ss
// X<>::foo(); // i d Ss
foo(100);
// PUSH... 100
// PUSH... _x
Y<longlong>::foo ();
// Y<>::foo();
fun<char,short, long> ();
fun<char,short> ();
fun<char>();
fun<>();
fun();
bar(1.23);
return0;
}
tarena@tarena-virtual-machine:~/day48/day02$./a.out
c s l
c s Ss
c d Ss
100 200
x x
c s l
c s Ss
c d Ss
i d Ss
i d Ss
d
2、非类型参数
1)模板除了可以接受类型参数以外,也可以接受非类型参数,即数值参数。非类的非类型参数不能用typename声明,而要注明其具体类型,而且传递给模板非类型参数的实参必须是常量、常量表达式,或者带有常属性(const)的变量,但是不能同时具有挥发性(volatile)。
原因:(模板参数是在编译期间作用)
vi array.cpp
#include <iostream>
#include <iomanip>
using namespace std;
template<typename T = int, size_t S =3>
class Array {
public:
T&operator[] (size_t i) {
returnm_a[i];
}
Tconst& operator[] (size_t i) const {
returnconst_cast<Array&> (*this)[i];
}
Tm_a[S];
};
int square (int x) {
returnx * x;
}
template<int x>
int square (void) {
returnx * x;
}
/*
int square (void) {
return100;
}
*/
int main (void) {
Array<int>a;
/*
a.m_a[0]= 10;
a.m_a[1]= 20;
a.m_a[2]= 30;
*/
a[0]= 10; // a.operator[] (0) = 10;
a[1]= 20;
a[2]= 30;
Array<int>const b = a;
/*
cout<< b.m_a[0] << ' ' << b.m_a[1] << ' '
<<b.m_a[2] << endl;
*/
cout<< b[0] << ' ' << b[1] << ' '
<<b[2] << endl;
Array<string>c;
c[0]= "北京";
c[1]= "上海";
c[2]= "广州";
cout<< c[0] << ' ' << c[1] << ' '
<<c[2] << endl;
intconst /*volatile */x = 2, y = 1;
Array<Array<int,x+y+1>, 1+1+1> d;
// Array<Array<int,2+1+1>, 1+1+1> d;
for(int i = 0; i < 3; ++i)
for(int j = 0; j < 4; ++j)
d[i][j]= i * 4 + j + 1;
// d.operator[](i).operator[](j)= ...;
for(int i = 0; i < 3; ++i) {
for(int j = 0; j < 4; ++j)
cout<< setw (2) << d[i][j]
<<' ';
cout<< endl;
}
Array<Array<Array<int>> > e;
cout<< square (10) << endl;
cout<< square<10> () << endl;
return0;
}
tarena@tarena-virtual-machine:~/day48/day02$./a.out
10 20 30
北京 上海广州
1 2 3 4
5 6 7 8
9 1011 12
100
100
2) 向模板传递字符串形式的非类型参数:形参必须使用字符指针,实参必须使用非静态全局字符数组
3) 模板的非类型参数只能使用整数类型:[signed / unsigned]char /short / int /long
不能使用浮点数类型:float/ double
举例 vinotype.cpp
#include <iostream>
using namespace std;
template<char* str>
void foo (void) {
cout<< str << endl;
}
template</*float*/char x>
void bar (void) {
cout<< x << endl;
}
char g_ca[] = "abc";
int main (void) {
foo<g_ca>();
return0;
}
tarena@tarena-virtual-machine:~/day48/day02$./a.out
abc
3、typename
在模板被实例化之前,模板参数所表示的具体类型并不确定。编译器会把依赖于模板参数的嵌套类型(内部)类型理解为某个类的静态成员变量。当其“看到”用该变量定义其它变量的代码时,会报告错误。typename关键字可以“告诉”编译器,其后的标识符不是静态变量而是某种类型。编译器就会将有关该标识符的类型检查推迟到模板实例化的过程中,避免编译错误-----解决嵌套依赖。
class作用:1、声明类 2、声明模板的类型参数
typename作用: 1、解决嵌套依赖 2、声明模板的类型参数
举例 vi typename.cpp
#include <iostream>
using namespace std;
class A {
public:
typedefunsigned int uint;
classB {};
};
template<typename T>
void foo (void) {
typenameT::uint u;
typenameT::B b;
}
void bar (void) {}
int main (void) {
A::uintu;
A::Bb;
foo<A>();
return0;
}
4、typename关键字
1)声明函数模板和类模板
template<….>….
2)解决嵌套模板:依赖于模板参数的类型的内部模板
在模板代码中,通过依赖于模板参数的对象、引用或指针,访问其带有模板特性的成员,需要使用template关键字显示指明其后的名称是一个模板,避免编译器将模板参数表的左右尖括号理解为小于号和大于号,导致编译失败。
举例:template.cpp
#include <iostream>
#include <typeinfo>
using namespace std;
template<typename T>
class A {
public:
//嵌套模板函数
template<typenameU>
voidfoo (void) const {
Uvar;
cout<< typeid (m_var).name () << ' '
<<typeid (var).name () << endl;
}
private:
Tm_var;
};
template<typename T>
void bar (T const& a, T const* b) {
a.templatefoo<double> ();
b->templatefoo<double> ();
}
int main (void) {
A<int>a;
a.foo<double>();
bar(a, &a);
return0;
}
tarena@tarena-virtual-machine:~/day48/day02$./a.out
i d
i d
i d
- Day48、模板特化、智能指针、模板的其他特性
- 类模板 --- 下 --- 特化、模板参数、智能指针
- 模板的特化、偏特化
- 模板偏特化 指针 模板萃取 指针
- 模板偏特化 指针 模板萃取 指针
- C++模板的特化
- 【c++】模板的特化
- 模板的偏特化
- 函数模板的特化
- C++模板的特化
- 模板的特化
- C++模板的特化
- C++模板的特化
- 类模板的特化
- 模板函数的特化
- 模板的偏特化
- 函数模板的特化
- 函数模板的特化
- 1002 Java形式参数问题-类型名、抽象类、接口
- ~基础知识简析~
- 基于OpenCV的条形码区域检测(三)
- How to compile COBOL program into shared library
- Getmemory函数详解--内存操作的理解
- Day48、模板特化、智能指针、模板的其他特性
- 计算机网络(二)网络层
- TF-IDF与余弦相似性的应用(二):找出相似文章
- 关于linux环境下信号SIGCHLD的排队机制
- Oracle基础sql语句
- 实例管理
- 求a与b的最大公约数与最小公倍数
- JavaScript的变量作用域深入理解
- 使用Spring(六)集合