经典问题解析五(五十五)

        在面试中有可能会遇到这个面试题,编写程序判断一个变量是否是指针。咱们咋一看是否是有点懵逼,咱们能够想到利用 C 语言中的可变参数函数。在 C++ 中依然是支持的,C++ 编译器的匹配调用优先级是:一、重载函数;二、函数模板;三、变参函数。咱们能够将变量分为两类:指针和非指针。须要编写函数的功能是当是指针变量调用时便返回 true,是非指针变量调用时返回 false。ios

        下来咱们就来试着编写下这个函数面试

#include <iostream>
#include <string>

using namespace std;

template
< typename T >
bool IsPtr(T* v)
{
    return true;
}

bool IsPtr(...)
{
    return false;
}

int main()
{
    int i = 0;
    int* p = &i;
    
    cout << "p is a pointer: " << IsPtr(p) << endl;
    cout << "i is a pointer: " << IsPtr(i) << endl;

    return 0;
}

        咱们利用函数模板和可变参数函数来实现,下来看看编译结果是否是咱们所指望的ide

图片.png

        咱们看到已经实现了,因而满意的交给了面试官。面试官看了下,笑着说你这个程序对通常的数据类型是可行的,对于类类型仍是进行判断嘛?咱们接着来试下类类型的判断是否还可行,在程序中添加一个类,再生成一个类对象 t,指向类对象 t 的指针 pt,下来看看编译结果图片.png函数

        咱们看到编译直接报错了,也就是说对于类对象来讲并不行,变参函数没法解析对象参数。那么咱们想一想怎么办呢,既然不能直接 IsPtr 函数的调用,咱们还能够利用它的返回值类型的大小来进行判断,将模板函数的返回值类型设置为 char,返回一个字符;将全局函数的返回值类型设置为 int,直接返回 0。再定义一个宏用来判断函数 IsPtr 的返回值是否是等于 char  类型的大小,若是是则返回 1,不然返回 0。咱们来看看程序学习

#include <iostream>
#include <string>

using namespace std;

class Test
{
public:
    Test()
    {
    }
    virtual ~Test()
    {
    }
};

template
< typename T >
char IsPtr(T* v)
{
    return 'c';
}

int IsPtr(...)
{
    return 0;
}

#define ISPTR(p) (sizeof(IsPtr(p)) == sizeof(char))

int main()
{
    int i = 0;
    int* p = &i;
    
    cout << "p is a pointer: " << ISPTR(p) << endl;
    cout << "i is a pointer: " << ISPTR(i) << endl;
    
    cout << endl;
    
    Test t;
    Test* pt = &t;
    
    cout << "pt is a pointer: " << ISPTR(pt) << endl;
    cout << "t is a pointer: " << ISPTR(t) << endl;

    return 0;
}

        咱们再次编译看看结果spa

图片.png

        咱们看到已经编译经过了,而且也正确进行类对象类型的判断了。那么这个面试题咱们就完美的进行回答了。还有一个面试题:若是在构造函数中抛出异常会发生什么?这便综合考查到了咱们的基础知识了,涉及到对象的构造、异常以及其余方面的知识。那么在构造函数中抛出异常,最直接的影响就是构造过程会当即中止,那么当前的对象便没法生成了。因为是异常,析构函数一样也没法被调用了,对象所占用的空间会当即收回。那么在工程项目中的建议是:不要在构造函数中抛出异常,当构造函数可能产生异常时,咱们便要使用二阶构造模式指针

        下来咱们仍是以代码为例来进行分析对象

#include <iostream>
#include <string>

using namespace std;

class Test
{
public:
    Test()
    {
        cout << "Test()" << endl;
        
        throw 0;
    }
    virtual ~Test()
    {
        cout << "~Test()" << endl;
    }
};

int main()
{
    Test* p = reinterpret_cast<Test*>(1);
    
    try
    {
        p = new Test();
    }
    catch(...)
    {
        cout << "Exception..." << endl;
    }
    
    cout << "p = " << p << endl;

    return 0;
}

        咱们在构造函数先打印函数名,在进行异常的抛出。先将指针 p 指向地址为 1 处,若是对象生成,那么便会返回一个地址值。咱们来看看编译结果图片

图片.png

        在抛出异常后,咱们看到 p 的地址仍是为 1,证实并无对象的生成。咱们应避免在析构函数中抛出异常!!析构函数的异常将致使对象所使用的资源没法彻底释放。经过对一些经典问题的学习,总结以下:一、C++ 中依然支持变参函数;二、变参函数没法很好的处理对象参数;三、利用函数模板和变参函数可以判断指针变量;四、构造函数和析构函数中不要抛出异常。资源


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

相关文章
相关标签/搜索