无法通过Diamond中的std :: unique_ptr访问最基类的受保护成员变量 [英] Can't access protected member variables of the most base class through std::unique_ptr in diamond
问题描述
我不是高级程序员.假设有一个经典的钻石继承:
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
变量,该变量对于A
和B
都是公用的,因此一次只能调用A
或B
中的一个,而不是两者(这是需要的).为了解决这个问题,可以使用以下方法:
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
不能再访问了,因为它说它已经受到保护,但是A
和B
都直接在其构造函数中调用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_p
和this->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
.
为了确保我能清楚地说明所有问题:不仅我是一个初学者,而且,鉴于上面的示例,如果还有另一种方法可以调用Scanner
或Copier
内部一次只能一次.我并不是要征求意见,我知道这是被禁止的,但是我不会拒绝来自经验丰富的用户的意见.毕竟,我正在学习.
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:
- 由构造函数创建的
Last
对象,即this
指向的对象.由于 is-a 继承关系,它也是Base
对象. - 构造函数中名为
base
的本地对象.
- The
Last
object which is being created by the constructor, i.e. the one pointed to bythis
. It's also aBase
object because of the is-a inheritance relationship. - The local object named
base
within the constructor.
现在,问题在于,在base.m_x = 0;
行中,您位于第一个对象的上下文中,而不是第二个对象.换句话说,您正在尝试从base
外部访问base
的m_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屋!