第24节 经典问题解析四

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/pt_raspi_fresher/article/details/88626972

-------------------------------------资源来源于网络,仅供自学使用,如有侵权,联系我必删.

第一:

历史的痕迹

你可能会看到类似下面的模板定义

#include <cstdlib>
#include <iostream>

using namespace std;

template<class T>   //template<typename T>
T Minus(T a, T b)
{
    return a - b;
}

template<class T>
class Add
{
public:
    T add(T a, T b)
    {
        return a + b;
    }
};

int main(int argc, char *argv[])
{
    //类模板  减法
    cout<<Minus(3, 4)<<endl;
    cout<<Minus<float>(0.3, 0.4)<<endl;
    
    //类模板  加法
    Add<double> ap;
    
    cout<<ap.add(9, 8)<<endl;
    cout<<ap.add(0.001, 0.1)<<endl;
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

为什么 class 可以用来定义模板参数呢?
为什么还要引进 typename呢?

第二:

在类中可以定义其它的新类型

#include <cstdlib>
#include <iostream>

using namespace std;

class Test
{
public:
    typedef int* PINT;//定义指针类型
    
    struct Point//定义结构体类型
    {
        int x;
        int y;
    };
    
    class Sub//定义内部类的类型
    {
        public:
            Sub()
            {
                cout<<"Sub()"<<endl;
            }
            
            void print()
            {
                cout<<"Hello World"<<endl;
            }
    };
};

int main(int argc, char *argv[])
{
    Test::PINT pi = new int(5);//指针pi 指向堆空间 初始化
    Test::Point po = {2, 3};//结构体po 初始化
    Test::Sub sub;//调用构造函数Sub()
    
    cout<<*pi<<endl;//打印pi指向空间的值
    cout<<po.x<<" "<<po.y<<endl;
    
    sub.print();
    
    delete pi;//释放
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

第三:

在类模板中定义新的类型

在函数模板中使用类模板的内部类型

#include <cstdlib>
#include <iostream>

using namespace std;

template<typename T, int N>
class Test
{
public:
    typedef T ElemType;//将T定义为一个新名字ElemType
    enum { LEN = N };//定义枚举类型
    
    ElemType array[LEN];//定义数组
};

template<typename T>   //template<class T>  报错!!!    需要用typename 关键字!!!
void test_copy(T& test, typename T::ElemType a[], int len)//for循环复制
{
    int l = (len < T::LEN) ? len : T::LEN;//取较小值
    
    for(int i=0; i<l; i++)
    {
        test.array[i] = a[i];
    }
}

int main(int argc, char *argv[])
{
    Test<int, 5> t1;//类模板内部定义新类型
    Test<float, 3> t2;
    
    int ai[] = {5, 4, 3, 2, 1, 0};//赋初始值
    float af[] = {0.1, 0.2, 0.3};
    
    test_copy(t1, ai, 6);
    test_copy(t2, af, 3);
    
    for(int i=0; i<5; i++)
    {
        cout<<t1.array[i]<<endl;
    }
    
    for(int i=0; i<Test<float, 3>::LEN; i++)
    {
        cout<<t2.array[i]<<endl;
    }
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

为什么 class 可以用来定义模板参数呢?
为什么还要引进 typename 呢?

 模板最初的目标只是为了对类类型进行泛型操作的定义,因此用 class 关键字声明泛型类型
 在之后的进化过程中发现了模板相互调用时产生的 ::  操作符的二义性
 因此引入 typename 关键字是用于告诉编译器将 ::符号后的标识符看作类型

第四:

拾遗

  C++ 中仍然支持C 语言中的可变参数函数
  C++ 编译器的匹配调用优先级
   第一级:  重载函数
   第二级:  函数模板
   第三级: 可变参数函数

 C++编译器匹配示例

#include <cstdlib>
#include <iostream>

using namespace std;


int test(int i, int j)
{
    cout<<"int test(int i, int j)"<<endl;
}

template<typename T>
T test(T i, T j)
{
    cout<<"T test(T i, T j)"<<endl;
}

int test(...)//可变参数函数
{
    cout<<"int test(...)"<<endl;
}

int main(int argc, char *argv[])
{
    int i = 0;
    int j = 0;
    
    test(i, j);//重载函数优先选择  int test(int i, int j)
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

第五:

函数模板与可变参数函数的化学反应

//写函数判断一个变量是否为指针吗?

#include <cstdlib>
#include <iostream>

using namespace std;

template<typename T>
void isPtr(T*)//指针参数
{
    cout<<"void isPtr(T*)"<<endl;
}

void isPtr(...)//可变参数
{
    cout<<"void isPtr(...)"<<endl;
}

int main(int argc, char *argv[])
{
    int* pi = NULL;
    float* pf = NULL;
    int i = 0;
    int j = 0;
    
    isPtr(pi);//指针
    isPtr(pf);//指针
    isPtr(i);//非指针
    isPtr(j);//非指针
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

解决方案1 

//写函数判断一个变量是否为指针吗?
#include <cstdlib>
#include <iostream>

using namespace std;

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

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

int main(int argc, char *argv[])
{
    int* pi = NULL;
    float* pf = NULL;
    int i = 0;
    int j = 0;
    
    cout<<isPtr(pi)<<endl;
    cout<<isPtr(pf)<<endl;
    cout<<isPtr(i)<<endl;
    cout<<isPtr(j)<<endl;
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

你的方法实现了指针的判断,但是我觉得不够高效,你有更好的办法吗?

分析:
解决方案1  已经很好的解决面试官的问题,那么为什么还不够高效呢?哪里不够高效呢?

解决方案1   中的唯一耗时的地方在于函数调用的建栈与退栈过程,因此需要考虑如何避免这个过程以提高程序效率。

 解决方案2  

//写函数判断一个变量是否为指针吗?
#include <cstdlib>
#include <iostream>

using namespace std;

template<typename T>
char isPtr(T*);

int isPtr(...);

#define ISPTR(v) (sizeof(isPtr(v)) == sizeof(char)) //宏定义,避免函数调用,使用sizeof避免开销

int main(int argc, char *argv[])
{
    int* pi = NULL;
    float* pf = NULL;
    int i = 0;
    int j = 0;
    
    cout<<ISPTR(pi)<<endl;
    cout<<ISPTR(pf)<<endl;
    cout<<ISPTR(i)<<endl;
    cout<<ISPTR(j)<<endl;
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

猜你喜欢

转载自blog.csdn.net/pt_raspi_fresher/article/details/88626972