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
时间: 2024-11-16 07:04:01

C++Primer 第十六章的相关文章

C Primer Plus (第五版) 第十六章 C预处理器和C库 编程练习

第十六章 C预处理器和C库 开发一个包含您需要使用的预处理器定义的头文件 //max.h  #ifndef _MAX_H_     #define _MAX_H_     #define MAX(X, Y) ((X)>(Y)?(X):(Y)) #endif 2.两个数的调和平均数可用如下方法得到:首先对两数的倒数取平均值,最后再取倒数.使用#define指令定义一个宏"函数"执行这个运算.编写一个简单的程序测试该宏. #include <stdio.h> #defin

CSS3秘笈复习:十三章&amp;十四章&amp;十五章&amp;十六章&amp;十七章

第十三章 1.在使用浮动时,源代码的顺序非常重要.浮动元素的HTML必须处在要包围它的元素的HTML之前. 2.清楚浮动: (1).在外围div的底部添加一个清除元素:clear属性可以防止元素包围浮动元素.关键字:left.right或both. (2).浮动外围元素:让包含浮动元素的<div>也浮动.选择这种方法一定要在浮动容器后面的任何元素中添加一个clear属性,确保浮动元素落到容器的下方. (3).利用overflow : hidden.另一种常见的方法是在外围的样式中添加以下属性:

第十六章 多态性

相同函数名具有多态性: ①  译时的多态(由函数名来调用时体现):重载:同类,不同参 ②  运行时的多态(用指向不同类的指针来调用): 覆盖:  不同类,同参,基类有virtual(由指针的类型来决定,体现了多态性) 隐藏:①不同类,同参,基类无virtual②不同类,不同参(不论有无virtual)(由指针来决定,不能体现多态性) 1.  为什么要使用多重继承 多态性可以简单地概括为“一个接口,多种方法”,程序在运行时才决定调用的函数.C++多态性是通过虚函数(virtual)来实现的. 2.

《Java并发编程实战》第十六章 Java内存模型 读书笔记

Java内存模型是保障多线程安全的根基,这里仅仅是认识型的理解总结并未深入研究. 一.什么是内存模型,为什么需要它 Java内存模型(Java Memory Model)并发相关的安全发布,同步策略的规范.一致性等都来自于JMM. 1 平台的内存模型 在架构定义的内存模型中将告诉应用程序可以从内存系统中获得怎样的保证,此外还定义了一些特殊的指令(称为内存栅栏或栅栏),当需要共享数据时,这些指令就能实现额外的存储协调保证. JVM通过在适当的位置上插入内存栅栏来屏蔽在JVM与底层平台内存模型之间的

Gradle 1.12 翻译——第十六章. 使用文件

有关其他已翻译的章节请关注Github上的项目:https://github.com/msdx/gradledoc/tree/1.12,或访问:http://gradledoc.qiniudn.com/1.12/userguide/userguide.html 本文原创,转载请注明出处:http://blog.csdn.net/maosidiaoxian/article/details/41113353 关于我对Gradle的翻译,以Github上的项目及http://gradledoc.qin

Gradle 1.12用户指南翻译——第三十六章. Sonar Runner 插件

本文由CSDN博客万一博主翻译,其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Github上的地址: https://github.com/msdx/gradledoc/tree/1.12. 直接浏览双语版的文档请访问: http://gradledoc.qiniudn.com/1.12/userguide/userguide.html. 另外,Android 手机用户可通过我写的一个

《构建之法》第十六章读后感更正

第十六章IT行业的创新 1.关于灵感.灵光闪现固然重要,很多伟大的发明依靠的就是灵光一现的基础,但是灵光闪现的前提是个人的思考,长时间的思考.完成这一灵光的基础是不断的尝试,提高自己的技术.这样才会将自己的灵光变成一个实物而不是空想. 2.关于喜好.并不是人人都喜欢创新,因为创新本来就是个长耗时又难以被认可的东西.创新有需要考虑的因素有许多,个人.面子.优先级等等,现在人们更多的是支持在原有材料技术上的"线性发展"--扩充功能等. 3.关于想法.人们接受的并不是好的想法而是他们所需要的

MiS603开发板 第十六章 图像之VGA接口测试

作者:MiS603开发团队 日期:20150911 公司:南京米联电子科技有限公司 论坛:www.osrc.cn 网址:www.milinker.com 网店:http://osrc.taobao.com EAT博客:http://blog.chinaaet.com/whilebreak 博客园:http://www.cnblogs.com/milinker/ MiS603开发板 第十六章 图像之VGA接口测试 第十六章图像之VGA接口测试 在本章开始介绍视频图像处理开发平台的硬件结构,主要包括

第十六章——处理锁、阻塞和死锁(3)——使用SQLServer Profiler侦测死锁

原文:第十六章--处理锁.阻塞和死锁(3)--使用SQLServer Profiler侦测死锁 前言: 作为DBA,可能经常会遇到有同事或者客户反映经常发生死锁,影响了系统的使用.此时,你需要尽快侦测和处理这类问题. 死锁是当两个或者以上的事务互相阻塞引起的.在这种情况下两个事务会无限期地等待对方释放资源以便操作.下面是死锁的示意图: 本文将使用SQLServer Profiler来跟踪死锁. 准备工作: 为了侦测死锁,我们需要先模拟死锁.本例将使用两个不同的会话创建两个事务. 步骤: 1. 打