第24课 - 专题四经典问题解析

第24课 - 专题四经典问题解析

    一.历史的痕迹

      
  Source Example 1.1:
        #include <iostream>

        using namespace std;

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

        /* 从结果看与普通的typename T,没有区别 */
        template<class T>
        class Add{
        public:
            T add(T a,T b)
            {
                return a + b;
            }
        };


        int main(int argc, char** argv) {
            
            Add<double> a;
            /* 输出-1 */
            cout<<Minus<int>(1,2)<<endl;
            /* 输出5 */
            cout<<a.add(2,3)<<endl;
            return 0;
        }
        
        结论:class也可以定义模板,但是为什么需要typename关键字?
        
        1.2 在类中可以定义其他新类型
        Source Example 1.2:
            #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()
                    {
                        printf("hello world!\n");
                    }
                };
            };
                    

            int main(int argc, char** argv) {
                
                Test::PINT pi = new int(5);
                Test::Point po = {2,3};
                Test::Sub sub;
                
                cout<<*pi<<endl;
                cout<<po.x<<" "<<po.y<<endl;
                
                sub.print();
                
                delete pi;
                
                return 0;
            } 
           

            输出结果如下:


                

        1.3 在类模板中定义新类型

      
      #include <iostream>

            using namespace std;

            template <class T,int N>
            class Test
            {
            public:
                typedef T ElemType;
                enum {
                    LEN = N
                };
                T array[LEN];
            };
                    

            int main(int argc, char** argv) {
                Test<int, 5> t1;
                Test<float, 3> t2;
                
                return 0;
            }

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

         
   #include <iostream>

            using namespace std;

            template <class T,int N>
            class Test
            {
            public:
                typedef T ElemType;
                enum {
                    LEN = N
                };
                T array[LEN];
            };

            template<class T>    
                                    /* 编译报错,T::ElemType不是一个类型 */
                                    /* ElemType应该是一个类的内部类型还是类的静态成员变量,具有二义性 */
                                    /* 编译器会默认为是一个静态成员变量 */
                                    /* 加上typename表示后面的是一个类型,编译就会通过 */
            void test_copy(T& test,typename T::ElemType a[], int len)
            {
                int l = (len < T::LEN) ? len : T::LEN;
                
                for (int i; 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};
                float af[] = {0.1,0.2,0.3};
                
                test_copy(t1, ai, 6);
                
                return 0;
            }         

         1.4 为什么class可以用来定义模板参数呢?

            为什么还要仅仅typename呢?

        

            1.4.1 模板最初的目标指示为了对类类型进行泛型操作的定义,因此用class关键字声明泛型类型。

            1.4.2 在之后的进化过程中发现了模板相互调用产生::操作符的二义性

            1.4.3 因此引入typename关键字是用于高速编译器将::符号后的标识符看作是类型

            

    

    二.坑爹的面试题

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

        

         2.2拾遗:

            2.2.1 C++中仍然支持C语言中可变参数函数

            2.2.2 C++编译器的匹配调用优先级

                a.重载函数

                b.函数模板

                c.可变参数函数

            
          
 Source Example 2.2.2:
                #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, j = 0;
                    
                    /* 优先选择重载函数 */
                    Test (i, j);
                    
                    /* 最后匹配可变参数函数 */
                    Test (i, j, 0);
                    
                    return 0;
                } 
                        

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

    
        Source Example 2.3(判断指针的解决方案1):
                #include <iostream>

                using namespace std;

                template<typename T>
                void isPtr(T*)
                {
                    cout<<"is a ptr"<<endl;
                }

                void isPtr(...)
                {
                    cout<<"not is a ptr"<<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);
                    return 0;
                } 
           

                输出结果如下:


            

            这个方法不够高效,在函数调用的进栈与退栈比较耗

        
  Source Example 2.4(判断指针的解决方案2):
            #include <iostream>

            using namespace std;

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

            int isPtr(...);
                                /* sizeof关键字在编译期间大小就确定好了 */
            #define ISPTR(v) (sizeof(isPtr(v)) == sizeof(char))

            int main(int argc, char** argv) {

                int i = 0;
                int *p = NULL;
                
                cout<<ISPTR(i)<<endl;
                cout<<ISPTR(p)<<endl;
                cout<<ISPTR(1)<<endl;
                cout<<ISPTR("asfda")<<endl;
                cout<<ISPTR(0.5)<<endl;
                return 0;
            } 



猜你喜欢

转载自blog.csdn.net/qq_36521904/article/details/80487909