C++Primer 第十六章

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++Primer 第十六章相关的知识,希望对你有一定的参考价值。

//1.模板定义以关键字template开始,后跟一个模板参数列表,此列表不能为空。编译器用推断出的模板参数来实例化一个特定版本的函数。类型参数前必须使用class或者typename(推荐使用typename)。
template <typename T> bool comp(T t0, T t1){return t0 > t1;}

//2.除了定义类型参数外,还可以在模板中定义非类型参数。一个非类型参数表示一个值(必须是常量表达式,实际使用过程中,最好只使用整形,而不要使用其他类型)而非一个类型,通过特定的类型名而非typename来指定非类型参数。
template<int M> inline int fun(int (&p)[M]){return sizeof p;}    //注意inline的位置
int a[10] = {};
int v = fun(a);    //v = 40

//3.当编译器遇到一个模板定义时,它并不生成代码。只有当我们实例化出模板的一个特定版本时,编译器才会生成代码。这一特性影响了我们如何组织代码以及错误何时被检测到。
//  与模板代码不同,模板的头文件通常既包含声明,也包含定义。

//4.当调用一个函数模板的时候,编译器通常用函数实参为我们推断模板实参。
//  与函数模板的不同之处是,编译器不能为类模板推断模板参数类型,为了使用类模板,必须在模板名后的尖括号中提供额外信息,用来代替模板参数的模板实参列表(函数模板也能这么做)。
//  由以上可知,类模板的名字不是一个类型名,类模板用来实例化类型,而一个实例化的类型总是包含模板参数的。
//  因为类模板的名字不是类型名,而类模板名字加上尖括号以及显示模板实参才是一个类型名,所以在模板类外定义模板类的成员函数的时候必须以关键字template开始,后接类模板参数列表。
template<typename T>
class CA
{
public:
    CA(){}
public:
    T GetValue();
    void SetValue(T t){value = t;}
private:
    T value;
};
template<typename T> T CA<T>::GetValue()    {return value;}

CA<int> A;
A.SetValue(10);
int value = A.GetValue();    //value = 10

//5.默认情况下,一个类模板的成员函数只有当程序用到它的时候才进行实例化。如果一个类模板的成员函数没有被用到,则此成员函数将不被实例化。
//  上述特性使得:即使某种类型不能完全符合模板的要求,我们仍能使用该类型实例化类。

//6.当我们使用一个类模板类型时必须提供模板实参,但这个规则有一个例外:在类模板自己的作用域中,我们可以直接使用模板名,而不提供实参。

//7.模板和友员
//  模板类与模板友元函数:
//    A.类为模板,友元函数也是模板,且使用的模板参数一致。                则此友元函数仅对相同模板参数的类实例具有特殊访问权限。
//    B.类为模板,友元函数不是模板(使用指定模板实参类型的类实例)。        则友元函数只对指定类型的模板参数的类实例具有特殊访问权限。
//    C.类为模板,友元函数也是模板,且使用的模板类型参数不一致。        则此友元函数对所有类实例都具有特殊访问权限。
//    D.类不是模板,友元函数是模板。                                    则所有模板类型的友元函数都是对此类具有特殊访问权限。
//  模板类有模板类的友元关系(在A类中声明B类为其友元类)
//    a.A类为模板, B类是模板,且A类和B类使用的模板参数一致。            则此B类仅对相同模板参数的A类实例具有特殊访问权限。
//    b.A类是模板, B类是模板,且A类和B类使用的模板参数不一致。            则所有B类的实例都对A类具有特殊访问权限
//    c.A类是模板, B类不是模板。                                        则B类对所有A类的实例均具有特殊访问权限
//    d.A类不是模板,B类是模板,且B类使用了指定模板实参类型。            则只有指定类型的B类实例才对A类具有特殊访问权限
//    e.A类不是模板,B类是模板,且B类没有使用固定的模板类型。            则所有B类的实例都对A类具有特殊访问权限
template<typename T>
class CMyTest
{
private:
    T value;
public:
    T GetValue()    {return value;}

    /*A结论*/friend void SetVlaue_10(CMyTest<T>& MyTest)        {MyTest.value = 10;}
    /*结论B*/friend void SetValue_20(CMyTest<int> &MyTest);//注意点:此类型的友员函数不能定义在类的内部,否则会造成重定义                
    /*结论C*/template<typename X> friend void SetValue(CMyTest/*<T> 这里的<T>可加可不加*/ &temMyTest, X value)    {temMyTest.value = value;}
};
void SetValue_20(CMyTest<int> &MyTest)    {MyTest.value = 20;}

//前向声明
template<typename T>class CMyTest2;
class CMyTest1
{
public:
    void PrintfValueInt()    {printf("%d\n", valueInt);}
private:
    int valueInt;

    /*结论d*/friend class CMyTest2<CMyTest1>;
    /*结论e*/template<typename T> friend class CMyTest3;        //注意这里的friend的位置
};

template<typename T>
class CMyTest2
{
public:
    void SetCMyTest1ValueInt_1000(T& a)    {a.valueInt = 1000;}

    /*结论a*/friend class CMyTest3<T>;
private:
    int value;
};


template<typename T>
class CMyTest3
{
public:
    void SetCMyTest1ValueInt_3000(CMyTest1& a)    {a.valueInt = 3000;}
    void SetValue_10(CMyTest2<T>& temMyTest)    {temMyTest.value = 10;}

private:
    T value;

    /*结论c*/friend class CMyTest4;

};

class CMyTest4
{
public:
    template<typename T>void SetValue(CMyTest3<T>& temTest, T value)    {temTest.value = value;}
    /*结论D*/template<int X> friend void SetValue(CMyTest4 &MyTest)        {MyTest.value = X;}
private:
    int value;
};

template<typename T>
class CA
{
    template<typename X> friend class CB;
private:
    int value;
};

template<typename X> class CB
{
    template<typename T>
    /*结论b*/void Fun(CA<T> a)    {a.value = 10;}
};

//8.可以将模板类型参数声明为友员,即使使用内置类型也不会出错。
template<typename T> class CA
{
    friend T;
public:
    void SetValue(T v){value = v;}
private:
    T value;
};

class CB
{
public:
    CB(){}
    CB(int v) : value(v){}
public:
    void Fun(CA<CB>);
public:
    int value;
};
void CB::Fun(CA<CB> a)    {printf("%d\n", a.value.value);}

CB b;
CA<CB> a;
a.SetValue(10);
b.Fun(a);        //输出10

 

以上是关于C++Primer 第十六章的主要内容,如果未能解决你的问题,请参考以下文章

C和指针 第十六章 习题

算法导论第十六章

C语言第十六章:linux系统vi编辑器

第十六章 函数基础

MySQL必知必会第十六章 创建高级联结

第十六章-状态模式