构建虚拟基类的成员

时间:2013-04-12 13:15:03

标签: c++ inheritance

我知道这段代码不起作用,我也知道原因,但还有其他选择吗?

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

7 个答案:

答案 0 :(得分:2)

一些选项:

  1. a公开
  2. a -
  3. 创建公共setter / getter方法
  4. 让B成为A类的朋友(或只是函数f()
  5. 如果您只想允许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继承,所以在获得parentB之前成功动态投放其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.
    }
};

如果您有更好的解决方案,请随时发布。