无法通过钻石中的std :: unique_ptr访问大多数基类的受保护成员变量

时间:2016-11-05 16:04:39

标签: c++ unique-ptr diamond-problem

我不是高级程序员。假设有一个经典的钻石继承:

class Base
class A: virtual public Base
class B: virtual public Base
class Last: public A, public B

假设Base有一个变量m_x,这个变量对AB都很常见,只有A或{{{{}}之一。 1}},可以一次调用,而不是两者(这是需要的)。为了解决这个问题,请使用:

B

这很好,但现在class Last: public A, public B { private: std::unique_ptr<Base> m_p; public: Last(int i) { if (i) m_p = std::unique_ptr<Base>(new A()); else m_p = std::unique_ptr<Base>(new B()); } }; 已无法访问,因为它表示受到保护,但m_p->m_xA在其构造函数中调用B直接,没有问题。

这是一个已知的限制还是这样做的错误方法?如果错了,有什么解决方案吗?

以下是基于here图表的一些代码(页面略低):

m_x

同时使用#include <iostream> #include <memory> class Power { protected: double m_x; public: Power() {} Power(double x): m_x {x} {} virtual ~Power() = default; }; class Scanner: virtual public Power { public: Scanner() {} Scanner(double x): Power(x) {} // scan document }; class Printer: virtual public Power { public: Printer() {} Printer(double x): Power(x) {} // print document }; class Copier: public Scanner, public Printer { private: std::unique_ptr<Power> m_p; public: Copier() {} Copier(double x, int i) { if (i) m_p = std::unique_ptr<Power>(new Scanner(x)); else m_p = std::unique_ptr<Power>(new Printer(x)); } void print() { std::cout << this->Power::m_x << '\n'; } }; int main(int argc, char *argv[]) { Copier *copier {new Copier(1.618, 0)}; copier->print(); copier = new Copier(3.14, 1); copier->print(); return 0; } this->m_p(根据答案和评论)进行编译,但输出为this->Power::m_x

为了确保我把它全部拼写出来:不仅我是一个初学者,而且,鉴于上面的例子,如果还有其他选择来调用{{1},那么它真的必须保持这种状态。 }或0一次只能从Scanner内部一个。我不是在征求意见,我理解它是被禁止的,但我不会拒绝来自更有经验的用户。毕竟,我正在学习。

2 个答案:

答案 0 :(得分:3)

虚拟继承和std::unique_ptr都是红色鲱鱼。问题归结为:

class Base
{
protected:
    int m_x;
};

class Last : public Base
{
public:
    Last()
    {
        Base base;
        base.m_x = 0; // error
        m_x = 1; // no error
    }
};

错误类似于error C2248: 'Base::m_x': cannot access protected member declared in class 'Base'error: 'int Base::m_x' is protected within this context

解释是protected有点特殊。它只能在类级别工作,但也在对象级别工作。你在这里有两个相关的对象:

  1. 由构造函数创建的Last对象,即this指向的对象。由于是-a 继承关系,它也是Base对象。
  2. 构造函数中名为base的本地对象。
  3. 现在,问题是在行base.m_x = 0;中,您处于第一个对象的上下文中,而不是第二个对象的上下文中。换句话说,您正试图从m_x外部访问base base。 C ++根本不允许这样做。

    可以在§11.4[class.protected]的C ++标准中找到一个非常技术性的解释,这是Stack Overflow中excellent answer中更容易理解的解释。

答案 1 :(得分:2)

protected并不代表你的想法。

虽然Last来自Base,但Last的成员函数无权访问任何 {{1}的受保护成员object - 只是那些Base个对象的子对象的对象。

所以你可以写:Base因为Lastthis->Base::x个对象,而不是*this,因为Last是静态类型m_p->x }。

正如其他人所说,我认为这实际上是XY problem。有一个派生自两个类的对象,然后有一个指向其中一个类的另一个对象的指针确实非常奇怪。我想你需要澄清你想要做的事情。