首页 / C++ / C++ 关于泛型模板的相关问题
C++ 关于泛型模板的相关问题
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了C++ 关于泛型模板的相关问题,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含6699字,纯文字阅读大概需要10分钟。
内容图文
泛型编程最早提出的目的是为了减轻代码量,避免无意义的重载而提出的;
在检查的时候并不针对于泛型进行检查,只有在编译的时候才会针对于template的类型来进行实例化;
泛型函数模板:
补充:关于内联函数的问题
内联函数类似于c中的宏展开,本质上就是为了减少调用栈的开销而提出的,采用inline方式来构造;
泛型函数也可以使用内联函数,对于最简单的例子如下:
#include<stdio.h> #include<iostream> #include<vector> #include<string> using namespace std; template <typename T> inline T cmp(const T& t1, const T& t2) { if (t1 > t2) return t1; else return t2; } int main() { int a = 1, b = 0; string s1 = "123", s2 = "234"; cout << cmp(a, b) << endl; cout << cmp(s1, s2) << endl; system("pause"); }
泛型类模板:
#include<stdio.h> #include<iostream> #include<vector> #include<string> using namespace std; template <typename Type> class Queue { public: Queue(); type& front(); private: //...private person }; int main() { system("pause"); }
如上所示,和泛型函数模板类似,就是在类的定义前加了模板定义;
模板类型形参:
模板类型形参主要指模板尖括号中的声明元素;
主要注意两点:
1.对于模板声明,typename和class都可以,但是前者只适用于C++标准,后者通用;
2.对于size_type这种容器的成员,其实属于类,对于模板中使用size_type作为类型,需要使用typename来指定,该成员是类中的一个类型,而非一个类数据;
如下所示:
template <class Parm, class U> Parm fcn(Parm* array, U value) { typename Parm::size_type* p; Parm::v = value; }
3.关于非模板类型形参的问题:
对于template尖括号中的内容,不一定非要用模板来进行确定,也可以直接采用非模板参数来进行定义,如下所示:
#include<stdio.h> #include<iostream> #include<vector> #include<string> using namespace std; template<typename T, int N> void output(T(&parm)[N]) { cout << N << endl; } int main() { int x[42]; double y[34]; output(x); output(y); system("pause"); }
个人认为该行为最主要的就是隐式的传递了参数;
例如上述的数组大小,避免了函数形参中需要显式的传递数组大小,直接通过模板定义中进行传递;
但是针对于后面的论述,模板参数定义中,参数定义越少越好;
指定模板形参:
其中最主要的特点之一就是可以指定特定的返回值,但是尤其要注意的是模板形参列表得顺序。
一般而言,模板形参的第一个列表可以作为指定的返回值来使用:
#include<stdio.h> #include<iostream> #include<vector> #include<string> using namespace std; template <typename T, typename U, typename V> T output(U a, V b) { cout << a << endl << b << endl; return a + b; } int main() { cout << output<int>(1.5, 2.6) << endl; system("pause"); }
比较重要的还是注意返回值的指定类型。一般来说默认尖括号的第一个位置是返回值;
类模板成员——通过Queue类得构造来理解类泛型:
在这样给小章节,书中主要举例了Queue类的构造,通过例子来说明类模板的一些问题,比如友元、模板实参、成员模板以及static成员。
首先对于Queue队列中元素的定义:
template <typename Type>class QueueItem { QueueItem(const Type& t) :item(t), next(0) {}; Type item; QueueItem* next; };
直接使用模板在QueueItem中进行定义,对于QueueItem中的类型,可以在实例化Queue中进行保存。本次的例子采用链表进行保存;
#include<iostream> #include<string> #include<stdio.h> using namespace std; template <typename Type>class QueueItem { public: QueueItem(const Type& t) :item(t), next(0) {}; Type item; QueueItem* next; }; template <typename Type> class MQueue { public: MQueue() :head(0), tail(0) {} MQueue(const MQueue& Q) :head(0), tail(0) { copy_elems(Q); } MQueue& operator=(const MQueue&); ~MQueue() { destory(); } Type& front() { return head->item; } const Type& front() const { return head->item; } void push(const Type&); void pop(); bool empty() const { return head == 0; } private: QueueItem<Type>* head; QueueItem<Type>* tail; void destory(); void copy_elems(const MQueue&); }; //类函数类外定义形式采用: //template <typename type>ret-type class_name<Type>::memeber_name template <typename type> void MQueue<type>::destory() { while (!empty()) pop(); } template <typename type> void MQueue<type>::pop() { QueueItem<type>* p = head; head = head->next; delete p; } template <typename type> void MQueue<type>::push(const type& val) { QueueItem<type>* pt = new QueueItem<type>(val); if (empty()) { head = tail = pt; } else { tail->next = pt; tail = pt; } } template <typename type> void MQueue<type>::copy_elems(const MQueue& orig) { for (QueueItem<type>* pt = orig.head; pt; pt = pt->next) push(pt->item); }
值得注意
1.private中的QueueItem指针head和tail,直接通过实例化Queue的模板参数就可以给定了QueueItem的类型;
2.在当前类模板的生效范围内,如果想采用其他模板类,必须要对其指定类型;
对于友元问题:
模板的友元问题也可以很好的在这里得到体现。
对于非模板类,如果声明友元函数,可以i很好的构建一个的或者多个实体的有缘关系。
对于模板而言,又有不同的几种情况:
1.授予对友元素说有实例的访问权;
2.只授予模板实例化的特定实例的访问权;
针对于所有实例都有访问权:
template <typename Type> class Bar { template <typename T> friend class Fool; };
该实例其实说明了对于所有的Fool模板实例化的类函数,都可以访问Bar模板所有实例的成员函数和成员;
这里再声明一下友元类的一些细节。
如果A中声明了友元类B,则B的成员函数可以视为A的成员函数,等价于可以直接访问A中的所有私有成员。
同样的,如果是针对于友元函数,而非友元类:
template <typename Type> class Bar { //template <typename T> friend class Fool; template <typename T> friend void temp1_fcn1(const T&); };
针对于特定实例的友元关系:
一般有两种情况:
1.同类型模板友元:
template <typename Type> class Bar { friend class Fool<Type>; friend void temp1_fcn1<Type>(Type const&); };
可以清楚的看到,Fool的实例化类型和Bar类似,所以说明只有同类型的Fool才可以访问Bar的私有成员;
2.指定类型友元:
template <typename Type> class Bar { friend class Fool<char*>; friend void temp1_fcn1<char*>(char* const&); };
可以显而易见,虽然Fool依然是模板,但是制定了类型,Fool<char*>,友元函数同理;
所以可以理解为,只有char*类型的模板实例化可以访问Bar的私有成员;
因此,针对于前面的MQueue中,可以不再将QueueItem变为共用成员,直接采用友元声明:
template <typename Type> class MQueue; template <typename Type>class QueueItem { public: QueueItem(const Type& t) :item(t), next(0) {} friend class MQueue<Type>; private: Type item; QueueItem* next; };
但是要注意声明问题,即在声明友元类的时候,进行初始化;
关于成员模板的问题:
一般来说,不一定是类或者函数整体声明为模板,也可以在类内声明模板函数。
例如典型的assign成员函数;
template <typename It> MQueue(It beg, It end) : head(0), tail(0) { copy_elems(beg, end); } template <typename Iter> void assign(Iter, Iter);
template <typename Iter> void copy_elems(Iter, Iter);
//对于该情况,比较典型的需求是将不同类型的元素相互转换,例如vector和Queue相互转换。
所以对于两个不同的模板可以模板类内嵌套的方式进行解决;
对于详细的类外定义,注意,需要补全模板成员函数的声明:
template <typename type> template<typename Iter> void MQueue<type>::assign(Iter beg, Iter end) { destory(); copy_elems(beg, end); } template <typename type> template<typename Iter> void MQueue<type>::copy_elems(Iter beg, Iter end) { while (beg != end) { push(*beg); ++beg; } }去
q
内容总结
以上是互联网集市为您收集整理的C++ 关于泛型模板的相关问题全部内容,希望文章能够帮你解决C++ 关于泛型模板的相关问题所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。