3

我知道这段代码行不通,我也知道为什么,但有其他选择吗?

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.

4

7 回答 7

2

一些选项:

  1. a公开_
  2. 为 -创建一个公共的 setter/getter 方法a-
  3. 让 B 成为 A 类的朋友(或只是函数f()

如果您只想允许 A(或特定功能)访问A. 另一方面,使用其他 2 个选项,您只能将该成员设为公开(但将对所有人公开)

于 2013-04-12T13:35:18.250 回答
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(); }
};
于 2013-04-12T13:26:07.887 回答
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转换 to应该返回与上面提供的解决方案相同的一个。Ba

现在,为什么这行得通?

因为一个类隐含地是它自己的朋友。

于 2013-04-12T13:55:24.830 回答
1

dynamic_cast就是为了。如果您不想重新设计代码,只需将 C 样式转换为dynamic_cast

void f() { dynamic_cast<B*>(parent)->a; }

要使其正常工作,A必须至少具有一个虚拟功能(就像这个一样)。此外,如果parent实际上不指向类型的对象,则强制转换将产生一个空指针B

于 2013-04-12T14:48:48.287 回答
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.
    }
};

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

于 2013-04-13T16:44:01.323 回答
0

我认为这里的问题不在于如何访问元素a,而在于为什么您需要在设计中使用菱形层次结构树。您应该首先退后一步,评估您是否真的需要一棵钻石树。

如果你这样做了,那么代替你当前的方法,提供A一个很好的合适的(公共)抽象接口,可以从B. 当您开始直接访问受父级保护的属性时,您将紧密耦合组件,从而很容易破坏您的代码,并且很难在应用程序生命周期的后期更改您的设计。

于 2013-04-12T13:41:48.990 回答
0
class B : public virtual A
{
public:
    B(void){}
    virtual ~B(void){}
protected:
    void f(){ this->a; }
};

您可以从父类(B 的母类)访问受保护的成员。

于 2013-04-12T13:22:10.647 回答