打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
[c primer plus]c 函数模版,类模版,实例化,具体化,模版作参数,模...
 
[c++ primer plus]c++ 函数模版,类模版,实例化,具体化,模版作参数,模版的友元
2009年11月26日 星期四 19:00

[c++ primer plus]c++ 函数模版,类模版,实例化,具体化,模版作参数,模版的友元 收藏
模版不是类或函数,它们是c++编译器指令,它只是一个用于生成类或函数的方案,说明如何生成类或函数。 具体生成时,称为实例化(instantiation)或具体化(specialization)。因此,模版不能单独编译,必须与特定的实例化请求一起使用。最简单的办法就是将所有模版信息放入一个头文件里,使用时include这个头文件。如果编译器支持export关键词,则可以将“类模版”的声明与定义分开存放在.h和.cpp中。

1. 函数模版的重载(利用可以重载的特征标)

template <class Any>
void Swap(Any& a, Any& b);

//override
template <class Any>
void Swap(Any* a, Any* b, int n);

template <class Any>
void Swap(Any& a, Any& b)
...{
    Any temp; temp = a; a = b; b = temp;
}

template <class Any>
void Swap(Any* a, Any* b, int n)
...{
    Any temp;
    for (int i = 0; i < n; i++)
    ...{ temp = a[i]; a[i] = b[i]; b[i] = temp; }
}
main( )
{
    int i, j;
    double k[10], m[10];
    Swap(i, j);         //显示实例化为Swap<int>(int&, int&);
    Swap(k, m, 10);    //显示实例化为Swap<double>(double*, double*, int);
}
2. 函数模版的显式实例化,即可以命令编译器直接创建 template<class Any> 的实例,把 class Any 实例化。

//explicit instantiation
template void Swap<int>(int&, int&);
template void Swap<Cjob>(Cjob&, Cjob&);
3. 函数模版的显式具体化,它不使用模版来生成函数定义,而应使用独立的、专门的函数定义。显式具体化要有自己的函数定义,而显式实例化则不需要,这是两者本质的区别。两者的相同之处是:都生成了一个具体的函数,而不再是模板。

// explicit specialization,这两种格式显式实例化的格式等价,只需要一种就可以。
template <> void Swap<Cjob>(Cjob& a, Cjob& b);
template <> void Swap(Cjob&a, Cjob& b);

template <> void Swap<Cjob>(Cjob& a, Cjob& b)
...{
    string tStr;
    tStr   = a.name;
    a.name = b.name;
    b.name = tStr;
}

template <> void Swap(Cjob& a, Cjob& b)
...{
    string tStr;
    tStr   = a.name;
    a.name = b.name;
    b.name = tStr;
}

4. 函数模版的部分具体化,部分具体化与显式具体化的区别在于:前者还是一个函数模板,而后者则已经是一个函数。前者的函数定义中,必然还有typename类型待定,这个类型将在函数模板被调用的时候得到“隐式”的具体化。

template <class T1, class T2, class T3>
void Swap(T1& a, T2& b, T3& c);

//explicit specialization
template <class T1, class T2> void Swap<T1, T2, int>(T1& a, T2& b, int& c);

//部分具体化,可以引入各种限制
template <class T1, class T2> void Swap<T1,T2, T2>(T1& a, T2& b, T2& c);
tempate <class T1> void Swap<T1, T1*, T1*>(T1& a, T1* &b, T1* &c);

template <class T1, class T2, class T3>
void Swap(T1& a, T2& b, T3& c)
...{
..............
}

template <class T1, class T2> void Swap<T1, T2, int>(T1& a, T2&b, int& c)
...{
..............
}

template <class T1, class T2> void Swap<T1,T2, T2>(T1& a, T2& b, T2& c);
...{
.............
}

template <class T1> void Swap<T1, T1*, T1*>(T1 &a, T1* &b, T1* &c)
...{
..............
}
5. 类模版之内与之外:在之内声明时可以忽略类型,之外必须Stack<Type>带上类型。

template <class Type>
class Stack
...{
public:
    Stack& operator= (const Stack& st);
}

template <class Type>
Stack<Type> & Stack<Type> :: operator=(const Stack<Type>& st)
...{
}
main ( )
{
    Stack<string> st;    //隐式的实例化
}
6. 类模版的默认类型参数,不能为函数模版提供默认的类型参数。

template <class T1, class T2 = int>
class Topo
...{
........
};
Topo<double, double> m1;
Topo<double> m2;    //使用默认类型
7a. 类模板的显式实例化

template <typename T>
class SortedArray
...{
public:
    T val
};

template class SortedArray<int>;

main ( )
...{
    SortedArray<int> sa; //模板类与模板函数的区别在于:前者被调用时,总是要带有<parameter-type>,而后者则不带。因为后者可以从形式参数来实例化或具体化模板;而前者则只能靠这个后缀,由编译器决定生成哪种类型。(即使已经显式实例化了,也要带上后缀。)
}
7b. 类模板的显式具体化

template <class T>
class SortedArray
...{
........
};

//显式具体化,定义新的类功能。
template <> class SortedArray<specialized-type-name>
...{
........
};
main ( )
{
    SortedArray<specialized-type-name> sa;
}
7c. 类模版的部分具体化

template <class T1, class T2, class T3>
class SortedArray
...{
public:
    SortedArray()
    ...{
        printf("1 ");
    }

    T1 val1;
    T2 val2;
    T3 val3;
};

template <class T1, class T2>
class SortedArray<T1, T2, T2>
...{
public:
    SortedArray()
    ...{
        printf("2 ");
    }

    T1 val1;
    T2 val2;
};

template <class T1>
class SortedArray<T1, T1, T1>
...{
public:
    SortedArray()
    ...{
        printf("3 ");
    }

    T1 val;
};

template <>
class SortedArray<int, int, int>
...{
public:
    SortedArray()
    ...{
        printf("4 ");
    }
};

int main(int argc, char* argv[])
...{
    SortedArray<int, int, int> sa1;
    SortedArray<int, int> sa2;
    SortedArray<int> sa3;
    //SortedArray sa4;

    printf("Hello World! ");
    return 0;
}
8. 模版作为模版类的成员

template <typename T>
class beta
...{
private:
    template <typename V>
    class hold;
    hold<T> q;
    hold<int> n;
public:
    template<typename U>
    U blab(U u, T t);
};

//member define
template <typename T>
template <typename V>
class beta<T>::hold
...{
private:
    V val;
public:
    V Value() const ...{return val;}
};

template <typename T>
template <typename U>
U beta<T>::blab(U u, T t)
...{
    ........
};
9. 模版作为模版的参数,vc++不支持这种使用,g++支持。

template <typename V>
class Stack
...{
....
};

template <template <typename T> class Thing>
class Crab
...{
....
};

main()
...{
    Crab<Stack> vStack;
}
10. 模版类的非模版友元函数

template <typename T>
class HasFriend
...{
    public:
        HasFriend(const T& i) : item(i) ...{ ct++; }
        ~HasFriend() ...{ ct--; }
        friend void counts();
        friend void report(HasFriend<T> &);
    private:
        T item;
        static int ct;
};

void counts()
...{
// 每个类有独立的static变量,模版没有static变量,因为模版只是提供给编译器的方案,本身并不是类。只有模版实例化或具体化之后,才可以访问其static变量。
    cout << "HasFriend<int>: " << HasFriend<int>::ct;
    cout << "HasFriend<double>:" << HasFriend<double>::ct;
}

// 必须为每个类提供相应的友元。
void report(HasFriend<int> & hf)
...{
    cout << hf.itme;
}

void report(HasFriend<double> & hf)
...{
    cout << hf.item;
}

main()
...{
    HasFriend<int> hf1;
    counts();
    HasFriend<double> hf2;
    counts();
    report(hf2);   
}
10. 模版类的约束模版友元。

//首先在类定义前面声明-函数是模版函数
template <typename T> void counts();
template <typename T> void report(T&);

template <typename TT>
class HasFriendT
...{
public:
    HasFriendT(const TT& i) : item(i) ...{ ct++; }
    ~HasFriendT() ...{ ct--; }
//在类里再次声明为友元,这里也是某种程度上的实例化,
//但还没有彻底实例化,函数还是模版。
    friend void counts<TT> ();
    friend void reports<HasFriendT<TT> > (HasFriendT<TT>&);
//这里也可以写做:
//friend void reports<> (HasFriendT<TT>&);
//让编译器自己判断模版的参数类型!
private:
    TT item;
    static int ct;
};

template <typename T>
int HasFriendT<T>::ct = 0;

template <typename T>
void counts()
...{
//这里并不是要输出模版的大小、模版的static成员变量。因为程序运行时,并不存在模版的实体,
//都是实例化后的确确实实存在的类。因此,这里指的实例化的类。
    cout << "template size: " << sizeof(HasFriendT<T>) << "; ";
    cout << "template counts(): " << HasFriendT<T>::ct << endl;
}

template <typename T>
void report(T& hf)
...{
    cout << hf.item << endl;
}

int main()
...{
    counts<int>(); //隐式实例化counts,由模版函数变为具体的函数

    HasFriendT<int> hfi1(10); //隐式实例化类,并定义该实例化类的一个对象
    HasFriendT<int> hfi2(20);
    HasFriendT<double> hfdb(10.5);

    report(hfi1); //通过调用,隐式实例化函数
    report(hfi2);
    report(hfdb);

    return 1;
}
11. 模版类的非约束模版友元。

template <typename T>
class ManyFriend
...{
public:
    ManyFriend(const T& i) : item(i) ...{}
    template <typename C, typename D> friend void show2(C&, D&);
private:
    T item;
};

template <typename C, typename D>
void show2(C& c, D& d)
...{
    cout << c.item << ", " << d.item << endl;
}

int main()
...{
    ManyFriend<int> hfi1(10);
    ManyFriend<int> hfi2(20);
    ManyFriend<double> hfdb(10.5);
    cout << "hfi1, hfi2: ";
    show2(hfi1, hfi2);
    cout << "hfdb, hfi2: ";
    show2(hfdb, hfi2);
    return 0;
}
发表于 @ 2009年04月21日 20:44:00 | 评论( 0 ) | 编辑| 举报| 收藏

旧一篇:禁止类继承的方法 | 新一篇: linux-socket详解与实例给billpig的留言只有注册用户才能发表评论!登录注册姓   名:
校验码:
Copyright ? billpig
Powered by CSDN Blog  
近期热点文章推荐 近期热点文章推荐1、程序优化利器:ATOM 2、简单有效快速定位内存错误3、成功案例,免费下载!4、AMT视频解说——通过WebUI管理AMT客户机5、从Embedded说起6、(图)集成显卡硬件解码7、免费开源应用程序下载多核、游戏、高性能,尽在英特尔? 软件网络

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/billpig/archive/2009/04/21/4098655.aspx

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
类模板(原创) - c++探索 - C++博客
C模版从精通到精神分裂
C 模版的本质
函数模板和模板函数
C 超详细讲解模板的使用
对SFINAE(替换失败并非错误)的理解
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服