为什么在尝试访问基本模板 class 的受保护成员时出现访问错误?
Why is there an access error when trying to access a protected member of a base template class?
常规 类:
class Base
{
public:
Base() {}
protected:
int* a;
};
class Derived : public Base
{
public:
Derived() {}
void foo() {
int** pa = &a;
}
};
int main() {
Derived* d = new Derived();
d->foo();
delete d;
}
但是Base
和Derived
类使用模板时报错:
‘int* Base<int>::a’ is protected within this context
template<typename T>
class Base
{
public:
Base() {}
protected:
int* a;
};
template<typename T>
class Derived : public Base<T>
{
public:
Derived() {}
void foo() {
int** pa = &Base<T>::a;
}
};
int main() {
Derived<int>* d = new Derived<int>();
d->foo();
delete d;
}
这是为什么?
该错误大多与模板无关,并且在没有任何继承的情况下也会发生。简单的问题是表达式 &Base<T>::a
被解析为指向成员的指针,如以下代码片段所示:
#include <iostream>
#include <typeinfo>
using namespace std;
class B
{
public:
void foo()
{
int* B::* pa = &B::a;
int** pi = &(B::a);
cout << typeid(pa).name() << endl;
cout << typeid(pi).name() << endl;
}
protected:
int* a;
};
struct D : public B
{
// Access to B::a is perfectly fine.
int* B::* pa = &B::a;
// But this causes a type error:
// "cannot convert from 'int *B::* ' to 'int **'
// int** pi = &B::a;
// Parentheses help to get the address of this->a ...
int** pi2 = &(B::a);
// ... and writing this->a helps, too ;-).
int **pi3 = &this->a;
// Of course, outside of templates we can simply write a!
int** pi4 = &a;
};
int main()
{
B b;
b.foo();
}
输出为:
int * B::*
int * *
模板是错误表面的地方,因为我们被迫限定从属名称,因此无意中以指向成员的指针结构结束。
评论部分的两种解决方案都有效:您可以简单地写成&this->a
,或者像我在这里所做的那样,将合格成员放在括号中。我不清楚为什么后者有效:operator::()
具有最高优先级,因此括号不会改变它。
正如人们所期望的那样,完全有可能在派生 class 中获取受保护基 class 成员的地址。据我所知,涉及模板时的错误消息是不正确且具有误导性的(但当我认为这是编译器的错误时,我通常是错误的...)。
常规 类:
class Base
{
public:
Base() {}
protected:
int* a;
};
class Derived : public Base
{
public:
Derived() {}
void foo() {
int** pa = &a;
}
};
int main() {
Derived* d = new Derived();
d->foo();
delete d;
}
但是Base
和Derived
类使用模板时报错:
‘int* Base<int>::a’ is protected within this context
template<typename T>
class Base
{
public:
Base() {}
protected:
int* a;
};
template<typename T>
class Derived : public Base<T>
{
public:
Derived() {}
void foo() {
int** pa = &Base<T>::a;
}
};
int main() {
Derived<int>* d = new Derived<int>();
d->foo();
delete d;
}
这是为什么?
该错误大多与模板无关,并且在没有任何继承的情况下也会发生。简单的问题是表达式 &Base<T>::a
被解析为指向成员的指针,如以下代码片段所示:
#include <iostream>
#include <typeinfo>
using namespace std;
class B
{
public:
void foo()
{
int* B::* pa = &B::a;
int** pi = &(B::a);
cout << typeid(pa).name() << endl;
cout << typeid(pi).name() << endl;
}
protected:
int* a;
};
struct D : public B
{
// Access to B::a is perfectly fine.
int* B::* pa = &B::a;
// But this causes a type error:
// "cannot convert from 'int *B::* ' to 'int **'
// int** pi = &B::a;
// Parentheses help to get the address of this->a ...
int** pi2 = &(B::a);
// ... and writing this->a helps, too ;-).
int **pi3 = &this->a;
// Of course, outside of templates we can simply write a!
int** pi4 = &a;
};
int main()
{
B b;
b.foo();
}
输出为:
int * B::*
int * *
模板是错误表面的地方,因为我们被迫限定从属名称,因此无意中以指向成员的指针结构结束。
评论部分的两种解决方案都有效:您可以简单地写成&this->a
,或者像我在这里所做的那样,将合格成员放在括号中。我不清楚为什么后者有效:operator::()
具有最高优先级,因此括号不会改变它。
正如人们所期望的那样,完全有可能在派生 class 中获取受保护基 class 成员的地址。据我所知,涉及模板时的错误消息是不正确且具有误导性的(但当我认为这是编译器的错误时,我通常是错误的...)。