如果我有一个抽象基类和一个派生自它的具体模板类,它有一个使用指向基类的指针的方法 - 似乎派生类停止将自身看作是从它派生的:
class AbstractBase
{
protected:
virtual void test() = 0;
};
template < class T >
class Derived : public AbstractBase
{
public:
virtual void call( AbstractBase* d ) { d->test(); } // Error!
protected:
virtual void test() {}
};
int main()
{
Derived< int > a;
Derived< int > b;
b.call( &a );
return EXIT_SUCCESS;
}
此错误:
'virtual void AbstractBase :: test()'受保护
编译器没错,它绝对是protected
- 但如果Derived< T >
继承自AbstractBase
,为什么会抱怨?
答案 0 :(得分:3)
不允许这样做是因为AbstractBase
作为一种类型声明test
受到保护。这使得它对所有人都是私有的,除非当前类是AbstractBase
的直接后代。即便如此,该类只能通过同一个类的对象访问该成员,而不是一个不同的后代,而不是直接来自AbstractBase
本身。
template < class T >
class Derived : public AbstractBase
{
public:
virtual void call( Derived * d ) {
d->test(); // ok, d has same type as this
AbstractBase *b = this;
b->test(); // not ok
}
protected:
virtual void test() {}
};
如上所示,您可以将其用于相同类型的指针。或者,您可以为Derived
创建代理基类,以实现virtual
方法来调用test
。这将允许从不同的Derived
类型进行访问。
class DerivedBase : public virtual AbstractBase
{
public:
virtual void call( DerivedBase * d ) { d->test(); }
};
template < class T >
class Derived : public DerivedBase
{
protected:
virtual void test() {}
};
可以通过这种方式访问:
Derived< int > a;
Derived< int > b;
Derived< float > c;
b.call( &a );
c.call( &a );
答案 1 :(得分:1)
这与模板无关,但与一般受保护的成员访问无关。请参阅第11.4节最新公开发布的C ++草案Standard
的受保护成员访问权限[class.protected]除了前面第11章中描述的那些之外的附加访问检查 在非静态数据成员或非静态成员函数时应用 是其命名类的受保护成员(11.2)115如上所述 之前,因为引用而授予对受保护成员的访问权限 发生在朋友或某些C类的成员中。如果要形成 指向成员(5.3.1)的指针,嵌套名称指定者应表示C 或者从C派生的类。所有其他访问涉及(可能 隐式)对象表达式(5.2.5)。在这种情况下,类 对象表达式应为C或从C派生的类。
[实施例:
class B {
protected:
int i;
static int j;
};
class D1 : public B {
};
class D2 : public B {
friend void fr(B*,D1*,D2*);
void mem(B*,D1*);
};
void fr(B* pb, D1* p1, D2* p2) {
pb->i = 1; // ill-formed
p1->i = 2; // ill-formed
p2->i = 3; // OK (access through a D2)
p2->B::i = 4; // OK (access through a D2, even though
// naming class is B)
int B::* pmi_B = &B::i; // ill-formed
int B::* pmi_B2 = &D2::i; // OK (type of &D2::i is int B::*)
B::j = 5; // OK (because refers to static member)
D2::j = 6; // OK (because refers to static member)
}