• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            大龍的博客

            常用鏈接

            統(tǒng)計(jì)

            最新評(píng)論

            模板類的子類訪問(wèn)不到父類的成員變量問(wèn)題

            很少用模板類,今天用googlemock給一個(gè)api打樁,那個(gè)api的函數(shù)居然是nonvirutal的,gmock幫助手冊(cè)說(shuō)Mocking Nonvirtual Methods就得用模板類,所以改了源碼,加了模板。但是編譯時(shí)遇到錯(cuò)誤,原來(lái)都可以在子類成員函數(shù)中訪問(wèn)到的父類的成員變量,現(xiàn)在提示沒(méi)有定義過(guò)。

            比如

            template<typename T>

            class A

            {

            public: 

               virtual int foo(){return 0};

            protected:

               int m_a;

            };

            template<typename T>

            class B : public A<T>

            {

            public:

               virtual int foo() {return m_a;}

            };

            這樣用gcc就會(huì)報(bào)錯(cuò),B類的foo函數(shù)中m_a找不到。

            解決辦法是 B類的foo函數(shù)這么寫(xiě)

             virtual int foo() {return this->m_a;}

            或者

             virtual int foo() {return A::m_a;}

            原因請(qǐng)看這段話:

            //10.8.2 Name lookup, templates, and accessing members of base classes
            //The C++ standard prescribes that all names that are not dependent on template parameters
            //are bound to their present definitions when parsing a template function or class.1 Only
            //names that are dependent are looked up at the point of instantiation. For example, consider
            //
            //       void foo(double);
            //
            //       struct A {
            //         template 
            //         void f () {
            //           foo (1);        // 1
            //           int i = N;      // 2
            //           T t;
            //           t.bar();        // 3
            //           foo (t);        // 4
            //         }
            //
            //         static const int N;
            //       };
            //
            //Here, the names foo and N appear in a context that does not depend on the type of T. The
            //compiler will thus require that they are defined in the context of use in the template,
            //not only before the point of instantiation, and will here use ::foo(double) and A::N,
            //respectively. In particular, it will convert the integer value to a double when passing
            // it to ::foo(double).
            //
            //Conversely, bar and the call to foo in the fourth marked line are used in contexts that
            //do depend on the type of T, so they are only looked up at the point of instantiation,
            //and you can provide declarations for them after declaring the template, but before
            //instantiating it. In particular, if you instantiate A::f, the last line will call an
            //overloaded ::foo(int) if one was provided, even if after the declaration of struct A.
            //
            //This distinction between lookup of dependent and non-dependent names is called two-stage
            //(or dependent) name lookup. G++ implements it since version 3.4.
            //
            //Two-stage name lookup sometimes leads to situations with behavior different from non-template
            //codes. The most common is probably this:
            //
            //       template  struct Base {
            //         int i;
            //       };
            //
            //       template  struct Derived : public Base {
            //         int get_i() { return i; }
            //       };
            //
            //In get_i(), i is not used in a dependent context, so the compiler will look for a name declared
            //at the enclosing namespace scope (which is the global scope here). It will not look into the base
            //class, since that is dependent and you may declare specializations of Base even after declaring
            //Derived, so the compiler can't really know what i would refer to. If there is no global variable
            //i, then you will get an error message.
            //
            //In order to make it clear that you want the member of the base class, you need to defer lookup
            //until instantiation time, at which the base class is known. For this, you need to access i in a
            //dependent context, by either using this->i (remember that this is of type Derived*, so is
            //obviously dependent), or using Base::i. Alternatively, Base::i might be brought into scope
            //by a using-declaration.
            //
            //Another, similar example involves calling member functions of a base class:
            //
            //       template  struct Base {
            //           int f();
            //       };
            //
            //       template  struct Derived : Base {
            //           int g() { return f(); };
            //       };
            //
            //Again, the call to f() is not dependent on template arguments (there are no arguments that depend on
            //the type T, and it is also not otherwise specified that the call should be in a dependent context).
            //Thus a global declaration of such a function must be available, since the one in the base class is
            //not visible until instantiation time. The compiler will consequently produce the following error message:
            //
            //       x.cc: In member function `int Derived::g()':
            //       x.cc:6: error: there are no arguments to `f' that depend on a template
            //          parameter, so a declaration of `f' must be available
            //       x.cc:6: error: (if you use `-fpermissive', G++ will accept your code, but
            //          allowing the use of an undeclared name is deprecated)
            //
            //To make the code valid either use this->f(), or Base::f(). Using the -fpermissive flag will also
            //let the compiler accept the code, by marking all function calls for which no declaration is visible
            //at the time of definition of the template for later lookup at instantiation time, as if it were a
            //dependent call. We do not recommend using -fpermissive to work around invalid code, and it will also
            //only catch cases where functions in base classes are called, not where variables in base classes are
            //used (as in the example above).
            //
            //Note that some compilers (including G++ versions prior to 3.4) get these examples wrong and accept above
            //code without an error. Those compilers do not implement two-stage name lookup correctly.
            //


            原理是名字查找的規(guī)則問(wèn)題。由于還要加班調(diào)程序,下次再寫(xiě)名字查找的原理

            posted on 2012-03-04 11:09 大龍 閱讀(2400) 評(píng)論(0)  編輯 收藏 引用


            只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問(wèn)   Chat2DB   管理


            一本色道久久综合亚洲精品| 99久久国产综合精品成人影院| 久久综合视频网站| 18禁黄久久久AAA片| 热re99久久精品国99热| 日本精品久久久中文字幕| 精品乱码久久久久久夜夜嗨| 区亚洲欧美一级久久精品亚洲精品成人网久久久久 | 波多野结衣AV无码久久一区| 国产精品欧美久久久天天影视 | 日韩人妻无码精品久久免费一| 99久久婷婷国产综合精品草原 | 国产精品日韩深夜福利久久| 亚洲精品美女久久777777| 国产欧美久久一区二区| 97精品伊人久久大香线蕉| 91亚洲国产成人久久精品| 亚洲va久久久噜噜噜久久狠狠| 国产精品99久久不卡| 欧美一区二区三区久久综合| 一本久久综合亚洲鲁鲁五月天| 国产福利电影一区二区三区,免费久久久久久久精| 天天影视色香欲综合久久| 国产巨作麻豆欧美亚洲综合久久| 久久精品国产亚洲AV无码娇色| 伊色综合久久之综合久久| 久久天天躁狠狠躁夜夜av浪潮| 国产成人精品久久一区二区三区| 久久人人爽人人爽人人爽| 精品久久久无码中文字幕天天| 免费精品99久久国产综合精品| 久久超碰97人人做人人爱| 无码八A片人妻少妇久久| 色8激情欧美成人久久综合电| 久久91精品综合国产首页| 久久婷婷国产麻豆91天堂| 久久精品国产亚洲网站| 国产农村妇女毛片精品久久| 久久综合中文字幕| 久久久久婷婷| 思思久久99热只有频精品66|