zoukankan      html  css  js  c++  java
  • 第68课 拾遗:让人迷惑的写法

    1. typename的前世今生

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

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

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

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

          

    (2)typename诞生的直接诱因

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

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

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

    【编程实验】模板中的二义性  68-1.cpp

    #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.可以直接通过异常声明定义无异常函数

    【编程实验】新的异常写法  68-2.cpp

    #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)异常声明能够提高程序的可读性

  • 相关阅读:
    潭州课堂25班:Ph201805201 django 项目 第二课 git 版本控制 (课堂笔记)
    HTML中的转义字符
    Java防止SQL注入
    Web很脆弱,SQL注入要了解
    防止sql注入:替换危险字符
    Hadoop HA详解
    java代码---charAt()和toCharry()的用法
    java代码-----计算器,界面+功能+boolean
    java代码-----运用endWith()和start()方法
    java代码---indexOf()方法
  • 原文地址:https://www.cnblogs.com/hoiday/p/10222297.html
Copyright © 2011-2022 走看看