我知道这段代码不起作用,我也知道原因,但还有其他选择吗?
class A
{
public:
A(void){}
virtual ~A(void){}
protected:
A* parent;
int a;
};
class B : public virtual A
{
public:
B(void){}
virtual ~B(void){}
protected:
void f(){ ((B*)parent)->a; }
};
无法将parent
转换为B*
,因为A
是虚拟基类。不投射parent
也会出错。我希望我没有让所有成员公开。有人知道如何访问A :: a?
修改
使用好友不起作用,因为来自B
的类无法访问A::a
。
答案 0 :(得分:2)
一些选项:
a
公开a
- f()
)如果您只想允许A(或特定功能)访问A
的成员,则第3个选项比其他2更好。另一方面,对于其他2个选项,您只能将该成员公开(但它将公开给所有人)
答案 1 :(得分:1)
从我上面的评论中得到答案,因为我测试了它并且编译得很好。
如果没有强制转换,它可能会失败,因为您尝试访问B中受保护的A字段。您只需添加公共getter并将强制转换为B *
class A
{
public:
A(void){}
virtual ~A(void){}
int getA() { return a; }
protected:
A* parent;
int a;
};
class B : public virtual A
{
public:
B(void){}
virtual ~B(void){}
protected:
void f(){ (parent)->getA(); }
};
答案 2 :(得分:1)
这有效:
class A {
public:
A(void){}
virtual ~A(void){}
protected:
A* parent;
int a;
int parent_a(){ return parent->a;}
};
class B : public virtual A
{
public:
B(void){}
virtual ~B(void){}
protected:
void f(){ A::parent_a(); }
};
请注意:
a
不会暴露于外面的世界,a
必须是正确的,因为B
几乎从A
继承,所以在获得parent
到B
之前成功动态投放其a
字段应返回与上面提供的解决方案相同的字段。现在,为什么这样做?
因为一个阶级本身就是一个隐含的朋友。
答案 3 :(得分:1)
这就是dynamic_cast
的用途。如果您不想重新设计代码,只需将C样式的强制转换替换为dynamic_cast
:
void f() { dynamic_cast<B*>(parent)->a; }
为了使其正常工作,A
必须至少有一个虚函数(就像这个一样)。此外,如果parent
实际上没有指向B
类型的对象,则转换将生成空指针。
答案 4 :(得分:0)
class B : public virtual A
{
public:
B(void){}
virtual ~B(void){}
protected:
void f(){ this->a; }
};
您被允许从父类(B的母班)访问受保护的成员。
答案 5 :(得分:0)
我认为这里的问题不是如何访问元素a
,而是为什么在设计中需要一个钻石层次结构树。你应该先退后一步,评估你是否真的需要一颗钻石树。
如果你做,那么为A
提供一个可以从B
调用的合适的(公共)抽象接口,而不是当前的方法。当您开始直接访问父受保护属性时,您会紧密地耦合组件,从而很容易破坏您的代码,并且很难在应用程序的生命周期中更改您的设计。
答案 6 :(得分:0)
谢谢大家,提到了一些可用的可能性,比如使用朋友和为每个变量创建附加功能。这可能在某些情况下有效,但在我的情况下不行。将每个派生类添加为朋友的问题是,当它们想要添加类时,它会使库不那么用户友好。为每个变量添加函数会为某些类添加超过一百个额外函数。
我最后的解决方案是创建副本而不是演员。虽然它会运行得慢一点,但代码仍然保持干净。解决速度问题。访问局部变量比访问全局变量要快得多。
现在的样子:
class A
{
public:
A* parent;
virtual ~A(void){}
virtual A & operator = (const A & x)
{
a = x.a;
parent = x.parent;
return *this;
}
protected:
int a;
};
class B : public virtual A
{
public:
B(void){}
virtual ~B(void){}
using A::operator =;
virtual B & operator = (const B & x)
{
A::operator = (x);
return *this;
}
void f(void)
{
B p;
p = *parent;
int x = p.a;//Allowed.
}
};
如果您有更好的解决方案,请随时发布。