首先,我了解 C++ 标准 (ISO/IEC 14882:2003):第 11.5 节第 1 段,但事实并非如此(但编译器显然不这么认为)。
我尝试通过 this 指针在派生类方法中调用 protected 基类方法,静态转换为基类指针并在 MSVC2008 错误 C2248: 'A::f' 中:无法访问类“A”中声明的 protected 成员。
我必须在“奇怪的重复模板模式”的上下文中执行此操作,但我可以用更简单的代码重现此错误,如下所示:
class B
{
protected:
void f(){}
};
class D : public B
{
public:
void g()
{
f(); // ok
this->f(); // ok
static_cast<B*>(this)->f(); // C2248 in MSVC2008
dynamic_cast<B*>(this)->f(); // C2248
((B*)this)->f(); // C2248
}
};
D d; d.g();
编译器似乎将强制转换的 this 指针视为指向其他实例的指针,是吗?
编译器在这种情况下是错误的,你怎么看?
好吧,我的真实代码更像这样:
template<class T>
class B
{
public:
void g()
{
f(); // error C3861: 'f': identifier not found
this->f(); // error C3861: 'f': identifier not found
// static_cast to derived class
static_cast<T*>(this)->f(); // C2248 in MSVC2008
}
};
class D : public B<D>
{
protected:
void f(){}
};
我将 this 转换为 derived 类,但我不能使用 this->f();
顺便说一句,我看到这段代码对于像 class E : public B<D> {...};
这样的用法是不安全的: 可编译,但 static_cast 进行了错误的转换。
最佳答案
编译器是正确的。显式访问 B::f
成员函数,可以这样写:
this->B::f();
相关语言是:
11.4 Protected member access [class.protected]
[...] Access to a protected member is granted because the reference occurs in a friend or member of some class C. [...] Access to a protected member [...] involve[s] a (possibly implicit) object expression (5.2.5). In this case, the class of the object expression shall be C or a class derived from C.
因此通过转换为基类来保护成员访问 B
违反了这项授权,并且是不允许的。这也是不必要的,因为您可以使用 this->B::f()
如上。
在您实际的 CRTP 动机的情况下,您不能调用 f()
是正确的没有 static_cast
, 自 D
不是 B<D>
的基类(继承关系是反方向的)。自 D
不是 B<D>
的基类, 你不能调用它的 protected
来自 B<D>
的方法反正。一种简单的解决方法是 friend
B<D>
至 D
并使用 static_cast
在 this
上指针:
template<typename T>
class B {
public:
void g() {
static_cast<T *>(this)->f();
}
};
class D : public B<D>
{
friend class B<D>;
...
如果给B
访问 private
部分 D
担心你,你可以移动private
部分到另一个基类并隔离 D
中的 CRTP 机制:
template<class T> class B {
public:
void g() {
static_cast<T*>(this)->f();
}
};
class C {
private:
void h();
protected:
void f(){ std::cout << "D::f\n"; }
};
class D: protected C, public B<D>
{
friend class B<D>;
};
在这里B<D>
无法调用 C::h
因为友元既不能继承也不能传递。
关于c++ - 通过此指针调用 protected 基类方法并转换为派生类中的基类 (C++),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11795349/