无法通过Diamond中的std :: unique_ptr访问最基类的受保护成员变量 [英] Can't access protected member variables of the most base class through std::unique_ptr in diamond

查看:137
本文介绍了无法通过Diamond中的std :: unique_ptr访问最基类的受保护成员变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am not an advanced programmer. Suppose there is a classic diamond inheritance:

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

假设Base具有m_x变量,该变量对于AB都是公用的,因此一次只能调用AB中的一个,而不是两者(这是需要的).为了解决这个问题,可以使用以下方法:

Suppose Base has a variable, m_x, that is common to both A and B, such that only one of A, or B, can be called at a time, not both (which is what is needed). To get around this, this is used:

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_x不能再访问了,因为它说它已经受到保护,但是AB都直接在其构造函数中调用m_x,没有问题.

This is fine, but now m_p->m_x cannot be accessed anymore because it says it's protected, but both A and B call m_x in their constructors directly, with no problems.

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

Is this a known limitation or is this the wrong way to do it? If it's wrong, what solutions are there?

以下是基于该图的一些代码,此处 (在页面下方):

Here is some code based on the diagram found here (a bit lower on the page):

#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_pthis->Power::m_x(根据答案和注释)进行编译,但是输出为0.

Using both this->m_p and this->Power::m_x (according to answers and comments) compiles, but the output is 0.

为了确保我能清楚地说明所有问题:不仅我是一个初学者,而且,鉴于上面的示例,如果还有另一种方法可以调用ScannerCopier内部一次只能一次.我并不是要征求意见,我知道这是被禁止的,但是我不会拒绝来自经验丰富的用户的意见.毕竟,我正在学习.

To be sure I spell it out all: not only I am quite a beginner, but, given the example above, it oesn't really have to stay that way if there is another alternative to call Scanner or Printer only one at a time from inside Copier. I am not asking for opinions, I understand it's forbidden, but I won't reject them coming from more experienced users. After all, I am learning.

推荐答案

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

Both virtual inheritance and std::unique_ptr are red herrings. The problem comes down to this:

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是一种特殊情况.它不仅在类级别上起作用,而且在对象级别上也起作用.您在这里有两个相关的对象:

The explanation is that protected is a somewhat special case. It does not only work on class level but also on the object level. And you have two relevant objects here:

  1. 由构造函数创建的Last对象,即this指向的对象.由于 is-a 继承关系,它也是Base对象.
  2. 构造函数中名为base的本地对象.
  1. The Last object which is being created by the constructor, i.e. the one pointed to by this. It's also a Base object because of the is-a inheritance relationship.
  2. The local object named base within the constructor.

现在,问题在于,在base.m_x = 0;行中,您位于第一个对象的上下文中,而不是第二个对象.换句话说,您正在尝试从base外部访问basem_x. C ++根本不允许这样做.

Now, the problem is that in the line base.m_x = 0;, you are in the context of the first object and not the second one. In other words, you are trying to access the m_x of base from outside base. C++ simply does not allow this.

在C ++标准的§11.4[class.protected]中可以找到非常技术性的解释,在优秀答案中更容易理解. 在堆栈溢出上.

A very technical explanation can be found in the C++ standard at §11.4 [class.protected], a more easily understandable one in an excellent answer here on Stack Overflow.

这篇关于无法通过Diamond中的std :: unique_ptr访问最基类的受保护成员变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆