我有抽象类A,我从中继承了许多类。在派生类中,我试图访问A槽A指针中的受保护函数。但是我收到编译器错误。
class A
{
protected:
virtual void f()=0;
};
class D : public A
{
public:
D(A* aa) :mAPtr(aa){}
void g();
protected:
virtual void f();
private:
A* mAPtr; // ptr shows to some derived class instance
};
void D::f(){ }
void D::g()
{
mAPtr->f();
}
编译器错误说:无法访问A类中声明的受保护成员A :: f。
如果我将mAPtr声明为D *,而不是A *所有内容都会编译。我不明白为什么会这样。
答案 0 :(得分:6)
依赖private
访问可以处理相同类型的无关实例。
依赖protected
访问可以处理相同类型(以及更多派生类型)的不相关实例。
但是,依赖protected
访问 无法处理基类型的无关实例。
[n3290: 11.5/1]:
当朋友或成员函数派生时 class引用受保护的非静态成员函数或受保护 非基础数据成员基类,应用访问检查 除了第11章中所述的那些之外 指向成员的指针(5.3.1),访问必须通过指针 衍生类本身(或任何类)的引用,引用或对象 源自该类)(5.2.5)。如果访问是形成指针 对于成员,嵌套名称说明符应命名派生类(或 任何来自该类的类。)
所以D
或某些内容来自D
,但不是A
。
这是一个经常被人质疑的关于C ++的可爱奇怪,尽管如此,它仍然是为了避免陷阱而设计的。毕竟,您不知道*mAPtr
实际的类型。
答案 1 :(得分:2)
包含受保护部分的类意味着此类允许派生类以他们选择的任何方式操作其基类(只要受保护的接口允许)。
D类对象可以操纵自己的A部分。实际上,他们可能想要保留一些不变量。
假设有(或将来会有)另一个E类,也是继承自A类.E类对象也可以操纵它们自己的A部分,它们可能会强制执行不同的不变量。
现在,如果允许D类对象操纵任何对象的A部分,则无法确保不变量。 D对象可以对打破该E对象的E对象的A部分执行某些操作。这就是不被允许的原因。
但是,如果你真的想要,也许是一种调用A :: f的方法,而不是将它暴露给每个人,那将是通过朋友的功能。
class A;
namespace detail
{
void call_f(A*);
}
class A
{
friend void detail::call_f(A*);
private:
virtual void f() = 0;
};
namespace detail
{
void call_f(A* a) { a->f(); }
}
class D: public A
{
public:
void g() { detail::call_f(mAPtr); }
private:
void f() {}
A* mAPtr;
};
这依赖于用户足够严格以避免名称空间明确表明其包含实现细节的名称空间。
答案 2 :(得分:-2)
您忘记在课堂声明后使用;
:
class A
{
protected:
virtual void f()=0;
};
class D : public A
{
public:
void g();
protected:
void f();
private:
A* mAPtr; // ptr shows to some derived class instance
};
此外,您不需要存储基类指针。