【问题标题】:C++ - Accessing protected/private members of a base classC++ - 访问基类的受保护/私有成员
【发布时间】:2016-07-15 02:37:56
【问题描述】:

我正在尝试一个小例子来练习继承和多态的概念。这是我的代码的简化版本:

class Shape {
protected:
    int length;
    int width;
public:
    virtual void setLength(int l) = 0;
    virtual void setWidth(int w) = 0;
};

class Rectangle : public Shape {
public:
    Rectangle(int l, int w)
    : length(l), width(w)
    { }

    void setWidth(int w) { width = w; }
    void setLength(int l) { length = l; }
};

int main() {
    Rectangle r(0,0);
}

我正在尝试运行上述程序。但是,当我编译 rectangle.cc 时,出现以下错误

g++ -c rectangle.cc

rectangle.cc: In constructor 'Rectangle::Rectangle(int, int)':
rectangle.cc:13:5: error: class 'Rectangle' does not have any field named 'length'
rectangle.cc:13:16: error: class 'Rectangle' does not have any field named 'width'

据我了解,在公共继承中,基类的受保护成员成为派生类的受保护成员,并且应该能够像公共成员一样访问。这是不正确的吗?另外,如果 length 和 width 是基类的私有成员,那么需要如何修改代码?

【问题讨论】:

  • 如果您将其减少为 minimal reproducible example 会有所帮助,这样更容易看到错误。您发布的大部分代码都是无关紧要的。
  • @Q_A 为了让您了解我们所说的最小化是什么意思,我将您的代码减少到仅能重现相同错误的两打代码。我希望你不要介意。请注意,许多功能与您遇到的问题无关,也不需要创建Shapes 的数组来重现它等。
  • 谢谢,我会记住的

标签: c++ inheritance polymorphism private protected


【解决方案1】:

不,基类的受保护成员不会成为派生类的受保护成员。与私有成员不同,基类的受保护成员可由派生类访问,并且它们在派生类的命名空间中保持受保护(因此同样适用于派生类的派生类,依此类推)。

但是基类的protected成员仍然是基类的成员,仍然是基类的构造函数负责构造它们,而不是派生类的构造函数。

【讨论】:

  • 澄清一下:编译器错误与“基类的受保护成员不成为派生类的受保护成员”无关
  • 但是如果派生类可以访问基类的受保护成员,那么为什么会出现上述错误?我不应该能够访问长度和宽度吗?
  • 您收到错误不是因为您尝试访问它们,而是因为您尝试在派生类中构造它们。
  • s/构造/初始化
【解决方案2】:

据我了解,在公共继承中,基类的受保护成员成为派生类的受保护成员,并且应该能够像公共成员一样访问。不对吗?

这是大部分正确的。基类的公共和受保护成员可以在派生类中访问(public 继承在这里无关紧要——这只影响外部观察者的访问)。但是,类成员(具有任何访问权限)只能在他们自己的类中初始化。在这种情况下,只有Shape 可以初始化length 和width - 它们是protected 并不重要,如果它们是public 或private 也是如此。

您必须添加一个构造函数来执行此操作,您的 Rectangle 构造函数可以简单地委托给它。无论length 和width 的访问控制如何(只要Shape 构造函数是public 或protected),这都有效:

struct Shape {
    Shape(int l, int w) : length(l), width(w) { }
};

struct Rectangle {
    Rectangle(int l, int w) : Shape(l, w) { }
};

或者,为了完整起见,您可以分配它们,但绝对更喜欢让Shape 初始化它们。此外,这仅在相关成员为 public 或 protected 时才有效:

Rectangle(int l, int w) {
    length = l;
    width = w;
}

请注意,您的 setWidth() 和 setLength() 函数很好 - 您确实可以访问 Rectangle 的成员函数中的那些受保护成员。只是不用于初始化。

【讨论】:

  • 谢谢。如果 length 和 width 是基类的私有成员,代码会如何变化?
  • @Q_A 让Shape 初始化它自己的成员意味着访问控制无关紧要。但在这种情况下,将 setWidth() 和 setLength() 设为虚拟并没有多大意义 - 派生类实际上无法设置任何内容。
【解决方案3】:

移除部分:length(l), width(w) 如果你想在派生类中使用长度和宽度(继承),你可以通过取它的名字来使用它,例如长度..完成...如果您碰巧在派生类中具有相同的命名字段“长度”,那么要使用派生类的“长度”,请使用 this->length ...

当继承时...公共访问说明符指出基类中的公共变为公共在派生类中受保护的基类变为受保护...

当使用受保护的...公共和受保护的基类变得受保护

【讨论】:

    猜你喜欢
    • 2016-10-01
    • 2012-05-03
    • 2014-01-26
    • 2019-12-05
    • 2016-04-07
    • 2016-05-22
    • 2023-03-03
    • 2011-01-06
    相关资源
    最近更新 更多