为什么受保护的超类成员作为参数传递时无法在子类函数中访问?

发布于 2024-08-27 04:11:45 字数 371 浏览 8 评论 0原文

我收到一个编译错误,对此我有点困惑。这是在VS2003上的。

错误 C2248: 'A::y' : 无法访问类 'A' 中声明的受保护成员

class A
{
public:
  A() : x(0), y(0) {}
protected:
  int x;
  int y;
};

class B : public A
{
public:
  B() : A(), z(0) {}
  B(const A& item) : A(), z(1) { x = item.y;}
private:
  int z;
};

问题出在 x = item.y;

该访问被指定为受保护。为什么类 B 的构造函数无法访问 A::y?

I get a compile error, which I'm slightly confused about. This is on VS2003.

error C2248: 'A::y' : cannot access protected member declared in class 'A'

class A
{
public:
  A() : x(0), y(0) {}
protected:
  int x;
  int y;
};

class B : public A
{
public:
  B() : A(), z(0) {}
  B(const A& item) : A(), z(1) { x = item.y;}
private:
  int z;
};

The problem is with x = item.y;

The access is specified as protected. Why doesn't the constructor of class B have access to A::y?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

红玫瑰 2024-09-03 04:11:45

原因是:

class base_class
{
protected:
    virtual void foo() { std::cout << "base::foo()" << std::endl; }
};

class A : public base_class
{
protected:
    virtual void foo() { std::cout << "A::foo()" << std::endl; }
};

class B : public base_class
{
protected:
    virtual void foo() { std::cout << "B::foo()" << std::endl; }

public:
    void bar(base_class *b) { b->foo(); }
};

如果这是合法的,您可以这样做:

A a;
B b;
b.bar(&a);

并且您将从 B 调用 A 的 protected 成员,这是不允许的。

It's because of this:

class base_class
{
protected:
    virtual void foo() { std::cout << "base::foo()" << std::endl; }
};

class A : public base_class
{
protected:
    virtual void foo() { std::cout << "A::foo()" << std::endl; }
};

class B : public base_class
{
protected:
    virtual void foo() { std::cout << "B::foo()" << std::endl; }

public:
    void bar(base_class *b) { b->foo(); }
};

If that were legal, you could do this:

A a;
B b;
b.bar(&a);

And you'd be calling a protected member of A from B, which isn't allowed.

影子的影子 2024-09-03 04:11:45

其他答案解释了阻止您的 B 对象访问示例中 A 的受保护部分的原因,即使 B 'is-a ' A.当然,解决此问题的最简单方法是使 A 中您想要访问的部分public` 或具有可公开访问的访问器方法。

但是您可能认为这是不合适的(或者您可能无法控制 A 的定义)。这里有一些建议可以让您按照破坏 A 访问控制的递增顺序来解决该问题。请注意,所有这些解决方法都假设类 A 是可复制构造的。

在第一种情况下,您只需使用 A 的复制构造函数为 B 对象的该部分设置初始状态,然后修复它:

class B1 : public A
{
public:
  B1() : A(), z(0) {}
  B1(const A& item) : A(item), z(1) {
    // fix up the A sub-object that was copy constructed 
    //  not quite the way we wanted
    x = y;
    y = 0;
  }
private:
  int z;
};

我发现令人难以置信的混乱,并且可能非常容易出错(假设我们希望 B 对象中的 A 子对象与 A 对象不同)传递给构造函数 - 一种不寻常的情况,但这是问题中给出的)。然而,它可以完成的事实为接下来的更具颠覆性的示例提供了一些理由...

下一个示例创建一个临时 B 对象,该对象具有与 AA 完全相同的副本code> 我们想要访问的对象。然后,我们可以使用临时 B 对象来获取受保护的项目:

class B2 : public A
{
public:
  B2() : A(), z(0) {}
  B2(const A& item) : A(), z(1) {
    // create a special-use B2  object that can get to the 
    //  parts of the A object we want access to
    B2 tmp( item, internal_use_only);

    x = tmp.y;  // OK since tmp is of type B
  }

private:
  int z;

  // create a type that only B2 can use as a 
  //    'marker' to call a special constructor 
  //    whose only purpose in life is to create
  //    a B object with an exact copy of another
  //    A sub-object in it
  enum internal_use {
    internal_use_only
  };
  B2( const A& item, internal_use marker) : A(item), z(0) {};
};

我发现该解决方案比第一个解决方案更容易混淆,但它仍然令人困惑(在我看来)。为了获得我们想要的 A 对象的部分而使用 B 对象的混蛋版本是很奇怪的。

我们可以通过为 A 对象创建一个特殊的代理来解决这个问题,该代理可以提供我们想要的访问权限。请注意,这是“最具颠覆性”的解决方法,因为任何类都可以执行此操作来获取 A 的受保护部分,即使它们不是 A 的子类> 他们自己。对于 B 类,获取 A 对象的受保护部分具有一定的合法性,因为 B is-a A,正如我们已经看到的,有一些解决方法可以让我们仅使用 B 类 已经拥有的权限进行访问,所以我认为这是 中这些解决方法的更简洁版本code>B 类 的情况。

class B3 : public A
{
public:
  B3() : A(), z(0) {}
  B3(const A& item) : A(), z(1) { 
    // a special proxy for A objects that lets us
    //  get to the parts of A we're interested in
    A_proxy tmp( item);
    x = tmp.get_y();
  }

private:
  int z;

    class A_proxy : public A
    {
    public:
        A_proxy( const A& other) : A(other) {};
        int get_x() {return x;};
        int get_y() {return y;};
    };

};

The other answers explain the reasoning behind preventing your B object from accessing the protected parts of A in your example, even though B 'is-a' A. Of course, the easiest way to fix this problem is to make the parts of A you want access topublic` or have publicly accessible accessor methods.

However you might decide that's inappropriate (or you might not have control over the definition of A). Here are some suggestions to let you work around the problem, in increasing order of subverting A's access control. Note that all of these workarounds assume that class A is copy-constructable.

In the first case, you simply use the copy constructor for A to set up an initial state for that part of the B object, then fix it up afterward:

class B1 : public A
{
public:
  B1() : A(), z(0) {}
  B1(const A& item) : A(item), z(1) {
    // fix up the A sub-object that was copy constructed 
    //  not quite the way we wanted
    x = y;
    y = 0;
  }
private:
  int z;
};

I find that incredibly confusing and probably very error prone (assuming that we want the A sub-object in the B object to be different than the A object being passed to the constructor - an unusual situation, but it's what was given in the problem). However, the fact that it can be done gives some justification for the more subversive examples that follow...

The next example creates a temporary B object that has an exact duplicate of the A object we want access to. We can then use the temporary B object to get to the items that were protected:

class B2 : public A
{
public:
  B2() : A(), z(0) {}
  B2(const A& item) : A(), z(1) {
    // create a special-use B2  object that can get to the 
    //  parts of the A object we want access to
    B2 tmp( item, internal_use_only);

    x = tmp.y;  // OK since tmp is of type B
  }

private:
  int z;

  // create a type that only B2 can use as a 
  //    'marker' to call a special constructor 
  //    whose only purpose in life is to create
  //    a B object with an exact copy of another
  //    A sub-object in it
  enum internal_use {
    internal_use_only
  };
  B2( const A& item, internal_use marker) : A(item), z(0) {};
};

I find that solution to be a bit less confusing than the first, but it's still confusing (in my opinion). Having a bastard version of of B object just to get to the parts of the A object we want is odd.

We can do something about that by creating a special proxy for A objects that gives the access we want. Note that this is the 'most subversive' workaround because it's something that any class could do to get to protected parts of A, even if they aren't sub-classes of A themselves. In the case of the B class, there's some legitimacy to getting to the protected parts of A objects, since B is-a A, and as we've already seen there are workarounds that let us get access that use only rights that class B already has, so I consider this a cleaner version of those workarounds in class B's case.

class B3 : public A
{
public:
  B3() : A(), z(0) {}
  B3(const A& item) : A(), z(1) { 
    // a special proxy for A objects that lets us
    //  get to the parts of A we're interested in
    A_proxy tmp( item);
    x = tmp.get_y();
  }

private:
  int z;

    class A_proxy : public A
    {
    public:
        A_proxy( const A& other) : A(other) {};
        int get_x() {return x;};
        int get_y() {return y;};
    };

};
山田美奈子 2024-09-03 04:11:45

IBM 的文档对此进行了最好的总结:

受保护的非静态基类
会员可以访问会员并且
任何派生类的友元
该基类通过使用其中之一
以下:

  • 指向直接或间接派生类的指针
  • 对直接或间接派生类的引用
  • 直接或间接派生类的对象

因此,使用上面的示例作为基础:

B::B(const A& item) : A(), z(1) {
  // NOT OK because `item` is not a reference to the derived class B
  //int i = item.y; 

  // OK because `item` reinterpreted as a reference to the derived class B
  // Do not do this (bad!) -- for illustrative purposes only
  int i = reinterpret_cast< const B& >(item).y;

  // OK because it is equivalent to `this->x = i`,
  //  where `this` is a pointer to the derived class B
  x = i;
}

IBM's documentation summarizes it best:

A protected nonstatic base class
member can be accessed by members and
friends of any classes derived from
that base class by using one of the
following:

  • A pointer to a directly or indirectly derived class
  • A reference to a directly or indirectly derived class
  • An object of a directly or indirectly derived class

Thus, using your example above as the basis:

B::B(const A& item) : A(), z(1) {
  // NOT OK because `item` is not a reference to the derived class B
  //int i = item.y; 

  // OK because `item` reinterpreted as a reference to the derived class B
  // Do not do this (bad!) -- for illustrative purposes only
  int i = reinterpret_cast< const B& >(item).y;

  // OK because it is equivalent to `this->x = i`,
  //  where `this` is a pointer to the derived class B
  x = i;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文