我也来谈一谈c++模板(一)
c++中程序员使用模板能够写出与类型无关的代码,提高源代码重用,使用合适,大大提高了开发效率。此前,可以使用宏实现模板的功能,但是模板更加安全、清晰。在编写模板相关的代码是我们用到两个关键词:template和class(或者typename),class和typename基本没有区别。
函数模板本质上就是实现针对不同类型的同一种算法的代码,其基本用法可以是形如:
template <class TYPE ,class TYPE,......>
ReturnValue function(Argments)
{
// code
}
这里template <class TYPE ,class TYPE,......> 声明了此段代码是一段模板。”<>“中提供的是模板的类型参数,当使用这段代码时,编译器会根据使用的实际类型产生一份实例。在接下来的整个函数模板中就可以使用类型参数了,函数的returnvalue,arguments,local variable都可以使用类型参数。下面是一段简单的函数模板使用实例:
template <class T> T foo(T& lhs,T& rhs)
{
T tmp = lhs;
lhs = rhs;
rhs = tmp;
return lhs>rhs?lhs:rhs;
} int main()
{
int a(),b();
cout << foo(a,b) << endl;
cout << "a=" << a << endl;
cout << "b=" << b << endl; string c("hello"),d("world");
cout << foo(c,d) << endl;
cout << "c=" << c << endl;
cout << "d=" << d << endl;
}
1-5行就是函数模板的基本使用方式,foo()函数的功能是交换两个参数,然后返回较大的值,但是foo()函数并不关心参数的类型 。当我们在main()中使用foo模板是,分别使用int和string类型都能得到期望的结果,而foo的代码只写了一份,没有针对int和string。
这是输出结果:
10
a=10
b=5
world
c=world
d=hello
类中含有成员函数模板的情况和上一种情况类似,只是限定了一下作用域。说实话,这一种情况应该比上一种情况更加常见,因为c++是一门面向对象的语言,我们定义的函数,通常需要定义在类中,尽量减少全局函数的使用。当然有点扯远了,写个小例子,说明用法:
class X
{
public:
template <class T>
void mf(T* t) {}
}; int main()
{
int i;
X* x = new X();
x->mf(&i);
}
基本和第一种情况一样,不再赘述了。
定义类模板的语法通项可以是这样的公式:
template<class TYPE,class TYPE...>
class CLASSNAME
{
//members.
};
template<class TYPE,class TYPE...>
ReturnValue CLASSNAME<TYPE,TYPE...>::function (Arguments)
{
//code.
}
类模板的使用大体和函数模板类似,只是要注意一点,当声明和定义相分离时,定义成员函数的时候,光限定模板名是不够的,要加上类型,只有这样限定才会是一个类名而非模板。举个例子:
template <class T>
class Bar {
void foo();
}; template<class t>
void Bar<T>::foo()
{
//
}
void Bar<T>::foo()是重要的,这是使用模板最常见的错误之一了。Bar只是模板而Bar<T>才是类名。
类中的成员函数也可以是一个模板,这样就形成了一种层次关系。需要注意的是,在定义成员函数函数模板的时候需要在上例的基础上,考虑模板间的层次关系。例如这样一段代码:
template<typename T>
class X
{
public:
template<typename U>
void mf(const U &u);
}; template<typename T>
template <typename U>
void X<T>::mf(const U &u)
{
} int main()
{
}
9-10行中限定了两个类型参数T、U的层次,其中U是成员函数函数模板的类型参数,如果11行这样写:
void X<U>::mf(const T &u)
就会报错。
还有一点需要注意的是:
Member template functions cannot be virtual functions and cannot override virtual functions from a base class when they are declared with the same name as a base class virtual function.
当使用与基类虚函数相同的名称进行声明时,成员模板函数不能是虚函数并且不能从基类重写虚函数。
关于之间的区别还是写两段代码具体的感受一下比较好。
嵌套类模板被声明为外部类范围内的类模板,可以在封闭类的内部或外部定义它们。通俗点说就是嵌套类模板的作用范围是它所在类的里边,嵌套类的定义可以在外边定义。,如下是一段msdn上面的嵌套类的简单例子:
#include <iostream>
using namespace std; class X
{ template <class T>
struct Y
{
T m_t;
Y(T t): m_t(t) { }
}; Y<int> yInt;
Y<char> yChar; public:
X(int i, char c) : yInt(i), yChar(c) { }
void print()
{
cout << yInt.m_t << " " << yChar.m_t << endl;
}
}; int main()
{
X x(, 'a');
x.print();
}
struct Y就是嵌套在class X中的一个类模板,在X类中模板Y实例化出了2个类型实例,分别是Y<int> 、Y<char>。此后所有的操作可以把Y<int>、Y<char>看做一个普通的类类型。
与上一种情况类似,只是这次外层类是一个类模板,而非具体的类类型。这种情况下最值得注意的就是:
When nested class templates are defined outside of their enclosing class, they must be prefaced by the template parameters for both the class template (if they are members of a class template) and template parameters for the member template.
当嵌套类模板在其封闭类的外部定义时,它们必须以类模板(如果它们是类模板的成员)的模板参数和成员模板的模板参数开头。------MSDN手册
翻译的也是比较拗口,但是读几遍的话也很好理解:当定义嵌套类时我们需要考虑的是,也就是第3中情况提到的需要注意的情况,”::“域作用符是作用于类上的,而非模板上的。所以如果在外部定义嵌套类时,首先我们不仅要在外层类模板后带上模板参数,使其形式上(还没有实例化)成为一个类,嵌套类也需要加上模板参数,使其形式上成为一个类。
#include <iostream>
using namespace std; template <class T>
class X
{
template <class U> class Y
{
U* u;
public:
Y();
U& Value();
void print();
~Y();
}; Y<int> y;
public:
X(T t) { y.Value() = t; }
void print() { y.print(); }
}; template <class T>
template <class U>
X<T>::Y<U>::Y()
{
cout << "X<T>::Y<U>::Y()" << endl;
u = new U();
} template <class T>
template <class U>
U& X<T>::Y<U>::Value()
{
return *u;
} template <class T>
template <class U>
void X<T>::Y<U>::print()
{
cout << this->Value() << endl;
} template <class T>
template <class U>
X<T>::Y<U>::~Y()
{
cout << "X<T>::Y<U>::~Y()" << endl;
delete u;
} int main()
{
X<int>* xi = new X<int>();
X<char>* xc = new X<char>('c');
xi->print();
xc->print();
delete xi;
delete xc;
}
最后还值得注意的是,正如第四种情况那样,嵌套类与外层类的模板参数也有层次关系。通常写成两行:
template <class T>
template <class U>
T被当成外层类的模板参数,U被当成嵌套类的模板参数。我看有的书上便于区分会写成缩进的形式:
template <class T>
template <class U>
关于模板的知识多,暂时没精力写了,明天再接着写下去。有哪些地方不到位的,还请各位看官指正,谢谢。本人QQ:5435620.EMAIL:baixiangcpp@gmail.com。
我也来谈一谈c++模板(一)的更多相关文章
- 谈一谈Java8的函数式编程(二) --Java8中的流
流与集合 众所周知,日常开发与操作中涉及到集合的操作相当频繁,而java中对于集合的操作又是相当麻烦.这里你可能就有疑问了,我感觉平常开发的时候操作集合时不麻烦呀?那下面我们从一个例子说起. 计 ...
- 谈一谈泛型(Generic)
谈一谈泛型 首先,泛型是C#2出现的.这也是C#2一个重要的新特性.泛型的好处之一就是在编译时执行更多的检查. 泛型类型和类型参数 泛型的两种形式:泛型类型( 包括类.接口.委托和结构 没有泛型枚 ...
- 从一张图开始,谈一谈.NET Core和前后端技术的演进之路
从一张图开始,谈一谈.NET Core和前后端技术的演进之路 邹溪源,李文强,来自长沙.NET技术社区 一张图 2019年3月10日,在长沙.NET 技术社区组织的技术沙龙<.NET Core和 ...
- 谈一谈Elasticsearch的集群部署
Elasticsearch天生就支持分布式部署,通过集群部署可以提高系统的可用性.本文重点谈一谈Elasticsearch的集群节点相关问题,搞清楚这些是进行Elasticsearch集群部署和拓 ...
- 谈一谈iOS事件的产生和传递
谈一谈iOS事件的产生和传递 1.事件的产生 发生触摸事件后,系统会将该事件加入到一个由UIApplication管理的事件队列中. UIApplication会从事件队列中取出最前面的事件,并将事件 ...
- 谈一谈对MySQL InnoDB的认识及数据库事物处理的隔离级别
介绍: InnoDB引擎是MySQL数据库的一个重要的存储引擎,和其他存储引擎相比,InnoDB引擎的优点是支持兼容ACID的事务(类似于PostgreSQL),以及参数完整性(有外键)等.现在Inn ...
- 谈一谈APP版本号问题
如题:谈一谈APP版本号问题 为什么要谈这个问题,周五晚上11~12点,被微信点名,说APP有错,无效的版本号,商城无法下单.我正在准备收拾东西,周末回老家,结果看到这样问题,菊花一紧.我擦,我刚加的 ...
- 谈一谈深度学习之semantic Segmentation
上一次发博客已经是9月份的事了....这段时间公司的事实在是多,有写博客的时间都拿去看paper了..正好春节回来写点东西,也正好对这段时间做一个总结. 首先当然还是好好说点这段时间的主要工作:语义分 ...
- 蓝的成长记——追逐DBA(5):不谈技术谈业务,恼人的应用系统
***************************************声明*************************************** 个人在oracle路上的成长记录,当中 ...
- 谈一谈并查集QAQ(上)
最近几日理了理学过的很多oi知识...发现不知不觉就有很多的知识忘记了... 在聊聊并查集的时候顺便当作巩固吧.... 什么是并查集呢? ( Union Find Set ) 是一种用于处理分离集合的 ...
随机推荐
- Effective java笔记(九),并发
66.同步访问共享的可变数据 JVM对不大于32位的基本类型的操作都是原子操作,所以读取一个非long或double类型的变量,可以保证返回的值是某个线程保存在该变量中的,但它并不能保证一个线程写入的 ...
- QT 中 关键字讲解(emit,signal,slot)
Qt中的类库有接近一半是从基类QObject上继承下来,信号与反应槽(signals/slot)机制就是用来在QObject类或其子类间通讯的方法.作为一种通用的处理机制,信号与反应槽非常灵活,可以携 ...
- c#获取光标在屏幕中位置
需要调用win32api,winform.wpf通用 代码如下: [DllImport("user32.dll")] public static extern bool GetCu ...
- [Q&A] MySQL Error 1050(42S01): Table already exist
[环境说明] 1:MySQL Server 5.5 2:MyEclipse 2014 3:JDK 1.7 造成该问题的可能原因: 1:用 Java 读取 SQL 文件,并执行其中的 sql 语句,但是 ...
- 绿色简单的学校登录html页面
效果预览:http://hovertree.com/texiao/css/22/ 代码如下: <!DOCTYPE html> <html> <head> <m ...
- Spring容器深入(li)
spring中最常用的控制反转和面向切面编程. 一.IOC IoC(Inversion of Control,控制倒转).对于spring框架来说,就是由spring来负责控制对象的生命周期和对象间的 ...
- CSS、j's单行、多行文本溢出显示省略号
在项目中,由于实际描述文字过多,导致初始页面纵向长度过长,也使得余下信息利用率降低:所以在文字过多的时候,初始化限制行数是有必要的 1. CSS单行文本溢出,显示省略号 <div style=& ...
- Webstorm常用的快捷键
WS的常用操作: 常用快捷键(Keymap/Eclipse): 复制当前行: Ctrl+Alt+↓ 向上/下移动当前行: Alt+↑/↓ 删除当前行: Ctrl+D 注释/取消当前行: Ctrl+/ ...
- 对CVE-2014-6271 [破壳漏洞] 的一次不太深入的跟踪
@firtst:有些事,该你遇到的始终会遇到!2013年,Struts2远程代码执行漏洞闹的满城风雨时,当时还对此一无所知:2014年4月,HeartBleed掀起波涛汹涌时,较快对此予以关注,晚上跑 ...
- Google C++单元测试框架GoogleTest---Extending Google Test by Handling Test Events
Google TestExtending Google Test by Handling Test Events Google测试提供了一个事件侦听器API,让您接收有关测试程序进度和测试失败的通知. ...