让我们看一下这个简单的代码示例,包括一个基类和一个派生自Base的类,它需要在构造函数中使用基类成员的地址。
#include <vector>
#include <inttypes.h>
#include <stdio.h>
class Base
{
protected:
std::vector<uint32_t> arr;
public:
Base(std::vector<uint32_t> arr_in): arr(arr_in) {}
};
class Derived: public Base
{
private:
uint32_t *parr;
public:
Derived(std::vector<uint32_t> arr_in): Base(arr_in)
{
parr = &arr[0];
}
uint32_t *get_parr();
};
uint32_t *Derived::get_parr(void)
{
return parr;
}
int main()
{
std::vector<uint32_t> myarr(3, 1);
Derived myderived(myarr);
printf("myderived.myarr adress = %p", myderived.get_parr());
}
由于派生类的构造函数首先调用基类构造函数,然后才执行其代码块,因此可以访问基类的成员。所以一切正常。
现在我更改代码示例,以便我的两个类是模板。
#include <vector>
#include <inttypes.h>
#include <stdio.h>
template<typename T>
class Base
{
protected:
std::vector<T> arr;
public:
Base(std::vector<T> arr_in): arr(arr_in) {}
};
template<typename T>
class Derived: public Base<T>
{
private:
T *parr;
public:
Derived(std::vector<T> arr_in): Base<T>(arr_in)
{
parr = &arr[0];
}
T *get_parr();
};
template<typename T>
T *Derived<T>::get_parr(void)
{
return parr;
}
int main()
{
std::vector<uint32_t> myarr(3, 1);
Derived<uint32_t> myderived(myarr);
printf("myderived.myarr adress = %p", myderived.get_parr() );
}
但是第二个示例在编译时给出了以下错误消息:
class_temp.cpp: In constructor ‘Derived<T>::Derived(std::vector<T>)’:
class_temp.cpp:23:13: error: ‘arr’ was not declared in this scope
parr = &arr[0];
那么为什么在带有模板类的第二个示例中,派生类构造函数不知道基类成员? 或者我在这里做错了什么?
谢谢。
答案 0 :(得分:6)
arr
现在是一个从属名称。这取决于T
。如果有T
Base<T>
专门没有arr
,会怎样?具体来说,来自[temp.dep]:
在类或类模板的定义中,不检查依赖基类(14.6.2.1)的范围 在非限定名称查找期间在类模板或成员的定义点或期间 类模板或成员的实例化。
Base<T>
是依赖基类 - 它取决于模板参数T
,因此在非限定名称查找期间不会检查其范围。解决这个问题的方法是使用限定名称查找。也就是说,要么是班级名称:
parr = &Base<T>::arr[0];
或仅与this
:
parr = &this->arr[0];
答案 1 :(得分:1)
在第二种情况下,Base
是一个模板,有人可能会为模板添加特殊化,所有这些都具有不同的成员变量。编译器在看到T
之前无法知道。
可能还有适合的全球arr
。您可以使用this->arr[0]
来帮助编译器指示它始终是成员变量。