第68课 拾遗:让人迷惑的写法

1. typename的前世今生

(1)定义模板时使用class的历史原因

  ①早期的C++直接复用class关键字来定义模板

  ②但是泛型编程针对的不只是类类型

  ③class关键字的复用使得代码出现二义性

(2)typename诞生的直接诱因

  ①自定义类类型内部的嵌套类型

  ②不同类中的同一个标识符可能导致二义性

  ③编译器无法辨识标识符究竟是什么

【编程实验】模板中的二义性

#include <iostream>
#include <string>

using namespace std;

template <class T>  //旧式写法,用class而不是typename定义模板
class Test
{
public:
    Test(T t)
    {
        cout << "t = " << t << endl;
    }
};

template <class T>
void func( T a[], int len)
{
    for (int i = 0; i<len; i++)
    {
        cout << a[i] << endl;
    }
}

////////////////////////////////////////////////////////
int a = 0;

class Test_1
{
public:
    //静态成员变量TS
    static const int TS = 1;
};

class Test_2
{
public:
    //内部类TS
    struct TS
    {
        int value;
    };
};

template <class T>
void test_class()
{
    //以下句子可能出现两种解读方法,会出现了二义性)
    T::TS * a;  //1. 通过泛型T内部类类型定义指针变量a.(大部分人的解读方式)
                //2. 使用泛型T内部的静态成员变量TS与全局变量a进行乘法操作

    //默认下,编译器会按2的方式解读,而不是我们期望的1的方式
    //如何解决以上的二义性问题呢?引入新的关键字typename,将它放在类型前面
    //以说明其紧跟的标识符是类型名而不是变量,形式如下
    //typename T::TS* a; //T::TS前用typename修饰,明确地表示其为一个类类型
                       //也可以用class来修饰。但这样会让人疑惑,因为class
                       //一般用于声明类的,但这里用法给人感觉好象是用来
                       //定义指针,所以建议用新的typename关键字。索性,
                       //把template <class T>也改为template <typename T>
                       //这样更彻底。即,在定义模板时完全抛弃class关键字
}

int main(int argc, char *argv[])
{
    test_class<Test_1>(); //编译通过,说明编译器是按2的方式去解读。
    test_class<Test_2>(); //编译不过,说明编译器是仍是按1的方式去解读

    return 0;
}

(3)typename的作用

  ①模板定义中声明泛指类型

  ②明确告诉编译器其后的标识符为类型

2. 令类的try-catch写法

(1)函数异常声明中的try-catch块

  ①try-catch用于分隔正常功能代码异常处理代码

  ②try-catch可以直接将函数实现分隔为2部分

  ③函数声明和定义时可以直接指定可能抛出的异常类型

  ④异常声明成为函数的一部分可以提高代码可读性

(2)注意事项

  ①函数异常声明是一种与编译器之间的契约

  ②函数声明异常后就只能抛出声明的异常

    A.抛出其它异常将导致程序运行终止

    B.可以直接通过异常声明定义无异常函数

【编程实验】新的异常写法

#include <iostream>
#include <string>

using namespace std;

int func(int i, int j) throw(int, char) //异常声明,表示该函数
                                        //可能抛出int和char两种类型的异常
{
    if ((0 < j) && (j < 10))
    {
        return (i + j);
    } else
    {
        throw ‘0‘; //抛出char型,合法。因为符合异常声明,也可以抛出整型
                   //如 throw 0;但除了这两种外的都不行,那会程序崩溃。
    }
}

//以下的写法已经不被推荐(g++下直接报错、VS2013下会出警告)
void test(int i) try   //正常代码
{
    cout << "func(i, i) = " << func(i, i) << endl;
}
catch (int i)   //异常代码
{
    cout << "Exception:" << i << endl;
}
catch (...)
{
    cout << "Exception..." << endl;
}

int main(int argc, char *argv[])
{
    test(5); //正常

    test(10); //抛异常

    return 0;
}
/*输出结果
func(i, i) = 10
Exception...
*/

3. 小结

(1)class可以用来模板中定义泛指类型(不推荐)

(2)typename是可以消除模板中的二义性

(3)try-catch可以将函数体分成2部分

(4)异常声明能够提高程序的可读性

时间: 2024-11-05 14:55:20

第68课 拾遗:让人迷惑的写法的相关文章

令人迷惑的写法(五十六)

今天我们来看看一些在程序中迷惑的写法,下面的程序想要表达什么意思呢? #include <iostream> #include <string> using namespace std; template < class T > class Test { public:     Test(T t)     {         cout << "t = " << t << endl;     } }; templat

Javascript中让人迷惑的一些基本数据类型跟内置包装对象

数据类型跟对象的区别: 基本的数据类型是没有 属性 和 方法的,但是对象有:就像是java中的基本数据类型跟引用类型一样: 看个例子: var s= "      xxxx" var xxxx=s.substring(s.lastIndexOf(" ")+1,s.length); 首先得明白在js中字符串可是基本类型,与数字类型一样.对比java,它的基本类型会有这种方法调用么?当然没有.java的String可是个对象,才能这么调.换成是int肯定不行. 我们可以

第68课 基础图形绘制(下)

1. 简易绘图程序 (1)功能需求 ①自由图形绘制 ②基本图形绘制(直线.矩形和椭圆) ③能够选择图形绘制颜色 (2)界面解决方案 ①以QWidget为基类创建绘图主窗口 ②使用QGroupBox创建图形设置区域 ③使用单选按钮QRadioBox实现目标图形的选择 ④使用组合框QCombox实现绘图颜色的选择 2. 自由绘图的实现 (1)自由绘图的本质是跟踪鼠标的移动轨迹:因此,必须考虑什么时候开始?什么时候结束?以及如何记录鼠标移动? (2)从绘图参数的角度,可以将己经绘制结束的图形与正在绘制

javascriptip学习第一课

1.基本知识: 数据类型: 1.类型分析: js中的数据类型有undefined,boolean,number,string,null,object,date,array等8种,前5种为基础类型,后3种为引用类型. 重点1:js中undefined,null,NaN的区别: 如图所示: 从上面的代码和运行结果中可以看出未定义的值和定义未赋值的为undefined,null是一种特殊的object,NaN是一种特殊的number. 重点2:js中undefined,null,NaN的运算比较: 从

多少人因为你的丢失,而翻遍了全世界。

多少人以友情的名义,爱着一个人. 多少人以友情的名义,拒绝一个人. 多少人不敢说出来,害怕说出来后连现在这样都不可以了. 多少人喜欢一个人,只是告诉了她让她知道,而后转身离去,再也不提. 多少人喜欢一个人,却是始终都没有告诉她. 多少人爱着,却好似在分离. 多少人走着,却好似困在原地. 多少人败给了一个"等"字. 多少人约定,转身后谁也不再回头,可是谁也忍不住. 多少人见证了很多爱情,却没有见证他们的婚礼. 多少人来到你的生命,便匆匆离去,再也不见. 多少人走进你的生活,只是为你的人生

舞蹈课(dancingLessons)

有n个人参加一个舞蹈课.每个人的舞蹈技术由整数ai来决定.在舞蹈课的开始,他们从左到右站成一排.当这一排中至少有一对相邻的异性时,舞蹈技术相差最小的那一对会出列并开始跳舞.如果相差最小的不止一对,那么最左边的那一对出列.一对异性出列之后,队伍中的空白按原顺序补上(即:若队伍为ABCD,那么BC出列之后队伍变为AD).舞蹈技术相差最小即是ai差的的绝对值最小. 你的任务是,模拟以上过程,确定跳舞的配对及顺序. 输入 第一行为正整数n(1<=n<=2*10^5)为队伍中的人数. 下一行包含n个字符

治愈系课程教材 第一课

第一部分:时态 时态有时间和特点组成 时间:现在.过去.将来 特点:一般.完成.进行.完成进行 所以时态总共有12种(加上过去将来的时间又多出4种时态,总共16种) ? 一般现在时 一般过去时 一般将来时 ? ? 现在完成时 过去完成时 将来完成时 ? 现在进行时 过去进行时 将来进行时 ? 现在完成进行时 过去完成进行时 将来完成进行时 ? ? 快速背出!!! ? 本节课我们学习四种时态,中英文对照分别是: 一般现在时:do/does 一般过去时:did 一般将来时:be going to d

第0课 - 数据结构引言

第0课 - 课程目标(实现一个轻量级STL) 第1课 - 进阶高手的大门 第2课 - 数据的艺术 第3课 - 初识程序的灵魂 第4课 - 程序灵魂的审判 第5课 - 算法的时间复杂度 第6课 - 算法效率的度量 第7课 - 课程学习小问答 第8课 - 泛型编程简介 第9课 - 智能指针示例 第10课 - C++异常简介 第11课 - 异常类构建 第12课 - 顶层父类的创建 第13课 - 类族结构的进化 第14课 - 线性表的本质和操作 第15课 - 线性表的顺序存储结构 第16课 - 顺序存储

第0-0课 - 引言

课程目录: 第0课 - 开发环境搭建 第1课 - GUI 程序原理分析 第2课 - GUI 程序实例分析 第3课 - QT 的诞生和本质 第4课 - Hello QT 第5课 - Qt Creator工程介绍 第6课 - 窗口部件及窗口类型 第7课 - Qt 中的坐标系统 第8课 - 启航!第一个应用实例 第9课 - 计算器界面代码重构 第10课 - 初探 Qt 中的消息处理 第11课 - Qt 中的字符串类 第12课 - 计算器核心解析算法(上) 第13课 - 计算器核心解析算法(中) 第14