很少用模板类,今天用googlemock给一个api打桩,那个api的函数居然是nonvirutal的,gmock帮助手册说Mocking Nonvirtual Methods就得用模板类,所以改了源码,加了模板。但是编译时遇到错误,原来都可以在子类成员函数中访问到的父类的成员变量,现在提示没有定义过。
比如
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就会报错,B类的foo函数中m_a找不到。
解决办法是 B类的foo函数这么写
virtual int foo() {return this->m_a;}
或者
virtual int foo() {return A::m_a;}
原因请看这段话:
//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.
//
原理是名字查找的规则问题。由于还要加班调程序,下次再写名字查找的原理