我不理解以下内容,当Derived
从Base
继承时,它可以访问受保护的成员,这些成员可以通过派生函数访问。但是,如果Base
类试图从Derived
类(它本身允许访问Base
)访问自己的成员,则它无法访问,为什么?
class Base {
protected:
int x;
};
class Derived : Base {
public:
void foo(Base* b);
};
void Derived::foo(Base* b) {
b->x = 2; // cannot access protected member,
// though Derived inherits from Base, why?
}
答案 0 :(得分:14)
常见的误解。
在Derived::foo()
内,您可以访问类Derived
对象的受保护基础成员。但是,*b
不类型为Derived
。相反,它的类型为Base
,因此它与您的类没有任何关系。
如果你以Derived*
作为参数,那就不一样了 - 那么你确实可以访问受保护的基础成员。
让我们拼出来:
struct Derived;
struct Base
{
int f(Derived *);
protected:
int x;
private:
int y;
};
struct Derived : public Base
{
int g(Base *);
int h(Derived *);
};
int Derived::g(Base * b)
{
return b->x; // error, protected member of unrelated class
return b->y; // error, private member of different class
}
int Derived::h(Derived * d)
{
return d->x; // OK, protected base member accessible in derived class
return d->y; // error, private member of different class
}
int Base::f(Derived * d)
{
return d->x; // OK, d converts to Base*
return d->y; // OK, ditto
}
答案 1 :(得分:6)
你对标准中的特殊规则进行了轻击:
11.5受保护的会员访问
当派生类的朋友或成员函数引用受保护的非静态成员函数或受保护的基类的非静态数据成员时,除了前面第11章中描述的那些之外,还应用访问检查。除非形成指向成员的指针,*访问必须通过指向派生类本身(或从该类派生的任何类)的指针,引用或对象。
此添加访问检查的一个原因是关于这些基类保护成员的行为。由于成员受到保护,因此不同的派生类可以添加语义,甚至可以对这些派生成员的含义进行批量更改。 (这是受保护数据相当危险的原因之一。)因为您的类忽略了对其他派生类中所做的基类语义的这些添加/修改,所以最好的做法是阻止对基类成员的访问。访问将通过基类。
答案 2 :(得分:1)
您有正确的想法,但您没有正确使用受保护的成员。
void foo(Base * b)应该是void foo();
及其实施将是:
void Derived :: foo(){ 返回此 - > X; }
因为x是受保护的成员,所以您无法从另一个对象访问它 - 即使该对象继承自该类。您只能从派生对象本身访问它。
答案 3 :(得分:1)
提供其他人所说的具体例子:
class Base {
protected:
int x;
};
class Derived : Base {
public:
void foo(Derived*, Base*);
};
int main() {
Base fiddle;
Derived fast, furious;
fast.foo(&furious, &fiddle);
}
void Derived::foo(Derived *d, Base* b) {
x = 1; // Legal, updates fast.x
this->x = 2; // Legal, updates fast.x
d->x = 3; // Legal, updates furious.x
b->x = 4; // Error, would have updated fiddle.x
}
答案 4 :(得分:0)
你基本上完成的是创建一个base的实例,它与派生的内部基础实例的派生关系不同。将变量设置为protected会使继承的类访问它自己的内部base实例。但是,在类中创建类型为base的对象是不同的,因此不允许访问。