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

        今天咱们来看看一些在程序中迷惑的写法,下面的程序想要表达什么意思呢?ios

#include <iostream>
#include <string>

using namespace std;

template < class T >
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 main()
{
    int a[5] = {1, 2, 3, 4, 5};
    
    Test<int> t(5);
    
    cout << endl;
    
    func(a, 5);

    return 0;
}

        咱们在类模板中用 class 来声明,可是咱们在 main 函数中是用 int 类型来使用的,下来咱们看看这样的写法在 C++ 编译器中支持吗?编程

图片.png

        咱们看到编译器编译经过而且运行成功。那么咱们不是用的 typename 来声明的泛指类型的嘛,这怎么用 class 了呢。这是由于历史上的一些缘由,早期的 C++ 直接复用 class 关键字来定义模板,可是泛型编程针对的不仅是类类型,class 关键字的复用使得代码出现二义性。下来咱们来看看具备二义性的代码ide

#include <iostream>
#include <string>

using namespace std;

int a = 0;

class Test_1
{
public:
    static const int TS = 1;
};

class Test_2
{
public:
    struct TS
    {
        int value;
    };
};

template
< class T >
void test_class()
{
    T::TS * a;  // 这便出现了二义性
                // 1. 经过泛指类型 T 内部的数据类型 TS 定义指针变量 a (推荐的解读方式)
                // 2. 使用泛指类型 T 内部的静态成员变量 TS 与全局变量 a 进行乘法操做
}

int main()
{
    test_class<Test_1>();
    test_class<Test_2>();

    return 0;
}

        咱们经过在函数模板指定泛指类型为 Test_1,即是第 2 种解读方式,泛指类型为 Test_2 时,即是第 1 种解读方式。那么在这块是否是就出现了二义性呢?咱们看看编译结果图片.png函数

        咱们看到编译器直接报错了,若是是一种类型的话,便让咱们在前前面加上 typename,那么咱们在模板中加上 typename,看看学习

图片.png

        编译器又报错了,它说 Test_1 中没有这种类型,确定没有啊,只有一个成员变量而已。咱们注释掉 Test_1 看看spa

图片.png

        编译经过了。那么 typename 诞生的缘由是什么呢?用来自定义类类型内部的嵌套类型,不一样类中的同一个标识符可能致使二义性,编译器没法直接辨识标识符到底是什么。typename 的做用有两个:一、在模板定义中声明泛指类型;二、明确告诉编译器其后的标识符为类型指针

        那么下面的程序想要表达什么意思呢?图片

图片.png

        try...catch 用于分隔正常功能代码与异常处理代码,try...catch 能够直接将函数实分隔为两部分。函数声明和定义时能够直接指定可能抛出的异常类型,异常声明成为函数的一部分能够提升代码可读性。那么函数异常声明时有几个注意事项:一、函数异常声明是一种与编译器之间的契约;二、函数声明异常后就只能抛出声明的异常,抛出其余异常将致使程序运行终止,能够直接经过异常声明定义无异常函数。编译器

        下来咱们仍是以代码为例来进行说明string

#include <iostream>
#include <string>

using namespace std;

int func(int i, int j) throw(int)
{
    if( (0 < j) && (j < 10) )
    {
        return (i + j);
    }
    else
    {
        throw '0';
    }
}

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()
{
    test(5);
    
    test(10);
    
    return 0;
}

        咱们在 func 函数中异常只声明了 int,而抛出了字符型异常。咱们来看看会致使程序运行终止嘛?

图片.png

        确实致使了程序的运行终止了,注意咱们的程序中还有 catch(...) 都没能捕捉到 char  类型的异常。那么咱们在声明的异常中加上 char 再来看看

图片.png

        程序正常的运行结束了。经过今天对一些迷惑写法的学习,总结以下:一、class 能够用来在模板中定义泛指类型(不推荐);二、typename 是能够消除模板中的二义性;三、try...catch 能够将函数体分红 2 部分;四、异常声明可以提供程序的可读性。


        欢迎你们一块儿来学习 C++ 语言,能够加我QQ:243343083