美文网首页
(GeekBand)Five class

(GeekBand)Five class

作者: Kidyours | 来源:发表于2016-08-21 22:05 被阅读0次

一、模板观念与函数模板

第一步:定义

函数模板的声明是在关键字template 后跟随一个或多个模板在尖括弧内的参数和原型。与普通函数相对,它通常是在一个转换单元里声明,而在另一个单元中定义,你可以在某个头文件中定义模板。例如:

// file max.h

#ifndef MAX_INCLUDED

#define MAX_INCLUDED

template

T max(T t1, T t2)

{

return (t1 > t2) ? t1 : t2;

}

#endif

定义 T 作为模板参数,或者是占位符,当实例化 max()时,它将替代具体的数据类型。max 是函数名,t1和t2是其参数,返回值的类型为 T。你可以像使用普通的函数那样使用这个 max()。编译器按照所使用的数据类型自动产生相应的模板特化,或者说是实例:

int n=10,m=16;

int highest = max(n,m); // 产生 int 版本

std::complex c1, c2;

//.. 给 c1,c2 赋值

std::complex higher=max(c1,c2); // complex 版本

第二步:改进设计

上述的 max() 的实现还有些土气——参数t1和t2是用值来传递的。对于像 int,float 这样的内建数据类型来说不是什么问题。但是,对于像std::complex 和 std::sting这样的用户定义的数据类型来说,通过引用来传递参数会更有效。此外,因为 max() 会认为其参数是不会被改变的,我们应该将 t1和t2声明为 const (常量)。下面是 max() 的改进版本:

template

T max(const T& t1, const T& t2)

{

return (t1 > t2) ? t1 : t2;

}

额外的性能问题

很幸运,标准模板库或 STL 已经在 里定义了一个叫 std::max()的算法。因此,你不必重新发明。让我们考虑更加现实的例子,即字节排序。众所周知,TCP/IP 协议在传输多字节值时,要求使用 big endian 字节次序。因此,big endian 字节次序也被称为网络字节次序(network byte order)。如果目的主机使用 little endian 次序,必须将所有过来的所字节值转换成 little endian 次序。同样,在通过 TCP/IP 传输多字节值之前,主机必须将它们转换成网络字节次序。你的 socket 库声明四个函数,它们负责主机字节次序和网络字节次序之间的转换:

unsigned int htonl (unsigned int hostlong);

unsigned short htons (unsigned short hostshort);

unsigned int ntohl (unsigned int netlong);

unsigned short ntohs (unsigned short netshort);

这些函数实现相同的操作:反转多字节值的字节。其唯一的差别是方向性以及参数的大小。非常适合模板化。使用一个模板函数来替代这四个函数,我们可以定义一个聪明的模板,它会处理所有这四种情况以及更多种情形:

template

T byte_reverse(T val);

为了确定 T 实际的类型,我们使用 sizeof 操作符。此外,我们还使用 STL 的 std::reverse 算法来反转值的字节:

template

T byte_reverse(T val)

{

// 将 val 作为字节流

unsigned char *p=reinterpret_cast (&val);

std::reverse(p, p+sizeof(val));

return val;

}

使用方法

byte_reverse() 模板处理完全适用于所有情况。而且,它还可以不必修改任何代码而灵活地应用到其它原本(例如:64 位和128位)不支持的类型:

int main()

{

int n=1;

short k=1;

__int64 j=2, i;

int m=byte_reverse(n);// reverse int

int z=byte_reverse(k);// reverse short

k=byte_reverse(k); // un-reverse k

i=byte_reverse(j); // reverse __int64

}

注:模板使用不当会影响.exe 文件的大小,也就是常见的代码浮肿问题。

二、类模板与操作符重载

例子

定义类模板的一般形式是:

template <类型名参数名1,类型名 参数名2,…>

class 类名

{

类声明体

};

例如,template

class Smemory

{…

public:

void input(T x);

}

表示定义一个名为Smemory的类模板,其中带类型参数T。

在类模板的外部定义类成员函数的一般形式是:

template <类型名参数名1,类型名 参数名2,…>

函数返回值类型 类名<参数名 1 参数名 2,…>::成员函数名(形参表)

{

函数体

}

例如:template

void Smemory::mput(T x)

{…}

表示定义一个类模板Smemory的成员函数,函数名为mput,形参x的类型是T,函数无返回值。

类模板是一个类家族的抽象,它只是对类的描述,编译程序不为类模板(包括成员函数定义)创建程序代码,但是通过对类模板的实例化可以生成一个具体的类以及该具体类的对象。

函数模板不同的是:函数模板的实例化是由编译程序在处理函数调用时自动完成的,而类模板的实例化必须由程序员在程序中显式地指定,

其实例化的一般形式是:

类名 <数据类型 1(或数据),数据类型 2(或数据)…> 对象名

例如,Smemory mol;

表示将类模板Smemory的类型参数T全部替换成int 型,从而创建一个具体的类,并生成该具体类的一个对象mol。

类模板示例:

类模板定义 定义一个类模板,一般有两方面的内容:

A. 首先要定义类,其格式为:

template //或用 template

class foo

{

……

}

foo 为类名,在类定义体中,通用类型T可以作为普通成员变量的类型,还可以作为conststatic成员变量以及成员函数的参数和返回类型之用。例如:

template

class Test{

private:

T n;

const T i;

static T cnt;

public:

Test():i(0){}

Test(T k);

~Test(){}

void print();

T operator+(T x);

};

B. 在类定义体外定义成员函数时,若此成员函数中有模板参数存在,则除了需要和一般类的体外定义成员函数一样的定义外,还需在函数体外进行模板声明

例如

template

Test::Test(T k):i(k){n=k;cnt++;}

如果函数是以通用类型为返回类型,则要在函数名前的类名后缀上“” (注:所有函数都要加“” )。例如:

template

T Test::operator+(T x){

return n + x;

}

C. 在类定义体外初始化const成员和static成员变量的做法和普通类体外初始化const成员和static成员变量的做法基本上是一样的,唯一的区别是需在对模板进行声明,例如

template

int Test::cnt=0;

template

Test::Test(T k):i(k){n=k;cnt++;}

三、泛型编程

四、容器

相关文章

  • (GeekBand)Five class

    一、模板观念与函数模板 第一步:定义 函数模板的声明是在关键字template 后跟随一个或多个模板在尖括弧内的参...

  • (GeekBand)First class

    一、头文件与类的声明 1.guard(防卫式声明) 在complex.h文件中写出: #ifndef__COMPL...

  • (GeekBand)Second class

    一、Big Three:拷贝构造函数,拷贝赋值函数,析构函数 1.拷贝构造函数 文字定义:拷贝构造函数,又称复制构...

  • (GeekBand)Third class

    一、转换函数(conversion function) 1.转出去,把本类转为其它类型 2.转回来,把其它类型转为...

  • (GeekBand)Fourth class

    一、虚表、虚指针、动态绑定 这一部分,我们介绍下 继承体系下,类和对象的存储形式。 1.1 vptr 虚指针 和 ...

  • My Yogo,My life

    This is my fifth Yogo Month. Attending Yogo class five ti...

  • class five 发音技巧

    辅音/b、c、d、f、g、h、j、k、l、m、n、p、q、r、s、t、v、w、x、y、z/ 元音/a、e、i、o、...

  • GeekBand class7

    1.依赖倒置原则:高层模块不应该依赖于低层模块,二者都应该依赖于抽象。 2.开放封闭原则:对扩展开放,对更改封闭 ...

  • GeekBand class8

    Shape * ashape =newCircle(); classMainForm :publicForm { ...

  • GeekBand class6

    1.alloc gcc采用这种办法分配内存,省去了无用的开支。 2.迭代器 迭代器提供对一个容器中的对象的访问方法...

网友评论

      本文标题:(GeekBand)Five class

      本文链接:https://www.haomeiwen.com/subject/crewsttx.html