<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12
      去年遇到了一個難以理解的bug,這個問題簡化起來是這樣:
      template<class T>
      class
      A { public: friend void test(int x) { cout << 1; } private: T a; };

        需求是,test函數想要成為A類的友元函數,來讀取A類中的private成員屬性,同時A類是一個泛型類,所以理所應當地想到這種寫法。在A類還沒有實例化對象的時候,這種寫法沒有任何報錯,當A類創建對象的時候,出現了奇怪的bug:

      int main() {
          A<int> x;
          A<long long> y;
          test(1);
          cout << "沒有問題" << endl;
      }

        A類創建了兩個對象,A類是泛型類,創建了一個int型的類,與一個long long型的類,結果出現了這個的報錯:

         redefinition,說明void test重定義了,但是為什么?還有更詭異的現象:當x,與y同時存在的時候,就會報這樣的錯,但是當x,y只存在一個的時候,也就是A類只創建一種類型的對象時,它并不會報錯,可以正常運行。當時也沒有深究這個問題,但到了現在,隨著本人對靜態多態的理解加深,這個問題可以得到解答。

        首先,先來了解一下c++的泛型:template的實現原理,簡單總結起來,就是五個字:自動生成代碼。

        之所以泛型會被稱為靜態多態,是因為它并不是運行時來進行,而是在編譯期進行的。假如定義了一個泛型函數test:

      void test(T t1, T t2) {
        //pass
      };

        在沒有對它實體化之前,它只是一個模板,而不是一個函數,編譯器就可以認為沒有test這個函數。但是當使用到它的時候,編譯器會根據test函數的使用情況自動地生成相應的參數的函數,比如下面,main函數中使用到了double參數類型的test與int參數類型的test:

      int main() {
        double x1 = 0, x2 = 0;
        int y1, y2;
        test(x1 = 0, x2 = 0);
        test(y1 = 0, y2 = 0);
        return 0;
      }

        編譯器會檢測到你一共使用了int與double兩種參數的test,所以自動生成一個如下代碼:

      void test(int t1, int t2) {
          //pass
      };
      void test(double t1, double t2) {
          //pass
      };

        這些事本來是由程序員自己來完成的,用template就可以偷懶,給你一個模板,讓編譯器自己生成代碼。這也是為什么,c++把它叫模板。因為template的函數或是類本身就不是一個函數或者類,它只是一個模板,告訴編譯器該怎么生成代碼,它本質上就是一種宏的替換,把template<class T>中的T替換成程序中所使用的類型,而這些操作就是在編譯期時完成的,而不是在運行時進行的,因為相應的代碼已經生成好了,不會有運行時開銷,所以稱為“靜態多態”。

        這樣做當然會有缺點,就是程序的編譯時間會變長,生成的可執行文件會變大,但是用編譯時間去換運行時間是很劃算的,因為編譯只需要編譯一次,而一個程序要被運行很多次。

        再說回之前的那個問題,知道了template的原理之后,之前的問題也就行容易理解了:在使用了A<int> x;的時候,編譯器檢測到了使用了int,所以生成了如下代碼:

      class A {
      public:
          friend void test(int x) {
              cout << 1;
          }
      private:
          int a; //將template<class T>中的T替換成int.
      };

        然后又檢測到了使用了A<long long> y;所以又生成了如下代碼:

      class A {
      public:
          friend void test(int x) {
              cout << 1;
          }
      private:
          long long a; //將template<class T>中的T替換成long long.
      };

        發現問題了嗎?void test(int x)被定義了兩次,成員函數是可以定義兩次的,因為A<int>與A<long long>是兩個不同的類,它們有一個名字相同的成員函數當然沒有問題,但是友元函數不同,友元函數并不屬于這個類,它屬于一個獨立的函數或是其它類的成員函數。所以出現了兩次它的定義,肯定會報redefinition的錯。

        解決方法當然也很簡單,一個函數,可以不能定義兩次,但是可以被申明無數次:類內聲類,類外實現:

      #include<iostream>
      using namespace std;
      template<class T>
      class A {
      public:
          friend void test(int x);
      private:
          T a; //將template<class T>中的T替換成long long.
      };
      void test(int x) {
          cout << 1;
      }
      int main() {
          A<int> x;
          A<long long> y;
          test(1);
          cout << endl << "沒問題" << endl;
          return 0;
      }

         運行結果:

       

      posted on 2023-03-26 17:43  Kuyenda  閱讀(32)  評論(0)    收藏  舉報

      主站蜘蛛池模板: 亚洲精品三区四区成人少| 疯狂做受XXXX高潮国产| 亚州中文字幕一区二区| 黑人异族巨大巨大巨粗| 丰满少妇高潮无套内谢| 国产亚洲欧洲AⅤ综合一区| 97久久精品无码一区二区| 五寨县| 国产精品尤物乱码一区二区| 国产精品欧美福利久久| 永久免费无码网站在线观看| 麻豆麻豆麻豆麻豆麻豆麻豆| 精品国产中文字幕懂色| 特黄aaaaaaa片免费视频| 免费99视频| 国产视色精品亚洲一区二区| 磐石市| 精品国产一区二区三区av性色| 国产精品护士| 国产欧美日韩另类精彩视频| 色二av手机版在线| 久久久久久久无码高潮| 国产精品乱人伦一区二区| 亚洲蜜臀av乱码久久| 亚洲午夜成人精品电影在线观看 | 久久香蕉国产线看观看怡红院妓院| 九九热精品在线视频免费| 成人精品一区二区三区在线观看| 久久天天躁狠狠躁夜夜婷| 亚洲欧美人成电影在线观看| 久久精品国产亚洲av品| 国产精品爽黄69天堂A| 重口SM一区二区三区视频| 久久精品色一情一乱一伦| 精品免费国产一区二区三区四区介绍 | 亚洲熟妇中文字幕五十路| 2021国产成人精品久久| 亚洲人成网线在线播放VA| 亚洲www永久成人网站| 国产成人亚洲无码淙合青草| 欧美激情一区二区|