C++模板类继承中诡异的作用域问题

软件和网站开发以及相关技术探讨
回复
xyath
帖子: 4
注册时间: 2009-11-09 10:39

C++模板类继承中诡异的作用域问题

#1

帖子 xyath » 2009-11-09 16:19

C++模板类继承中诡异的作用域问题

帖子由 tiger » 2009-08-19 18:30
下面一段代码,大家可以试试,这样的问题经常被人忽略,出错还很难查:

代码: 全选
/*
* template_scope.cpp
*
* Created on: 2009-8-19 下午06:13:28
* Author: kwarph
* Web: http://www.xuanyuan-soft.cn
* Mail: [email protected]
*/

#include <iostream>
using namespace std;

int x = 8;

void print() {
cout << "hello" << endl;
}

template<typename T>
class B {
public:
B() :
x(0) {
}

explicit B(const int& v) :
x(v) {
}

void print() const {
cout << "B::print()" << endl;
}

protected:
int x;
};

template<typename T>
class A: public B<T> {
public:
void test_scope() const {
cout << "x = " << x << endl; // 引用全局的x,输出 x = 8
// cout << "x = " << B<T>::x << endl; // 必须显式调用父类的x

print(); // 调用全局的print(),输出 hello
// B<T>::print(); // 必须显式调用父类的函数
}
};

class C {
public:
C() :
x(0) {
}

explicit C(const int& v) :
x(v) {
}

void print() const {
cout << "C::print()" << endl;
}

protected:
int x;
};

class D: public C {
public:
void test_scope() const {
cout << "x = " << x << endl; // 用父类的x,输出: x = 0
print(); // 调用父类的print(),输出: C::print()
}
};

int main() {
A<int> a;
a.test_scope();

D d;
d.test_scope();
}



但是非模板类继承就没有这些问题。
头像
cnkilior
论坛版主
帖子: 4984
注册时间: 2007-08-05 17:40

Re: C++模板类继承中诡异的作用域问题

#2

帖子 cnkilior » 2009-11-09 16:22

请用code标签
头像
zhu527812567
帖子: 883
注册时间: 2009-11-17 12:29
联系:

Re: C++模板类继承中诡异的作用域问题

#3

帖子 zhu527812567 » 2009-11-18 17:26

有类型写清的东西就先用
找不到再考虑模板,这是编译器的一贯做法
头像
pipilu
帖子: 63
注册时间: 2007-10-22 21:41

Re: C++模板类继承中诡异的作用域问题

#4

帖子 pipilu » 2009-11-19 17:26

嗯 C++ Template 中也提到过。
所以使用模板尽量用上 this->,不然会产生继承带来的问题。

想想也是,编译器现在对模板的东西是这样处理的:如果你不用(实例),就不对其进行编译(虽然只进行语法检查,但不进行语义检测),尤其是在成员模板函数上。
这个继承的问题,应该也是编译器偷懒的表现之一。
看看去了全局变量 print 之后的错误报告( g++ 4.3.3 ):

代码: 全选

test.cpp: In member function ‘void A<T>::test_scope()’:
test.cpp:36: error: there are no arguments to ‘print’ that depend on a template parameter, so a declaration of ‘print’ must be available
test.cpp:36: error: (if you use ‘-fpermissive’, G++ will accept your code, but allowing the use of an undeclared name is deprecated)
看,print 需要参数来制定。所以说 模板成员函数必须要显示指定参数( 类指针) : this->print().

没看过 C++ 的编译器源码,猜测可能是这样子:
编译到 A<int> 会实例化 A<int>, 继而是 B<int>, 形成一些类签名。这里只是实例化了类内的成员变量。成员函数又不影响类的结构变化,所以一般会将 成员函数游离在类基本结构之外,可以看看 C++ 对象结构的书,大部分编译器都是这样分开处理的。
然后编译 a.test_scope(), 编译到 print() 时,开始在当前符号表和outer 符号表中搜寻,因为模板类的成员函数是用到的时候才编译,才能加入到符号表中,所以这个时候就只找到 全局的print() 符号了。但是有了 this 就不同了,会从当前类域向基类域查找,如果是模板函数会实例化,并加入到符号表中。

猜测是这个样子,看样子得研究下 C++ 的编译器才行。

这个特性应该算是标准吧,现在。可以利用这个特性来进行一些模板元编程。
头像
zhu527812567
帖子: 883
注册时间: 2009-11-17 12:29
联系:

Re: C++模板类继承中诡异的作用域问题

#5

帖子 zhu527812567 » 2009-11-19 20:31

其实写代码的时候 写明this 指针是个好习惯,不能总是想着依赖符号可见范围。。

很容易出问题

另外就是LS的ERROR中提到了 -fpermissive,这个选项在编译Win32程序时常常要用到。。
回复