意外的引用行为

Unexpected reference behaviour

我正在研究复合模式并遇到以下代码的意外行为:

namespace Composit
{

    class Component
    {
    public:
        virtual ~Component() { }
        virtual void operation() = 0;
    protected:
    private:
    };

    class Leaf : public Component
    {
    public:
        Leaf() { }
        virtual ~Leaf() { }
        void operation() override
        {
            // Implementation of operation for a leaf
            std::cout << this << ": I am a leaf" << std::endl;
        }

    protected:

    private:
    };

    class Composit : public Component
    {
    public:

        Composit(Component& x) :
            child_(x)
        { }

        virtual ~Composit() { }

        void operation() override
        {
            // Implementation of operation for a composit
            std::cout << this << ": I am a composit! " << std::endl;
            child_.operation();
        }

    protected:
        Component& child_;

    private:
    };
}

int main()
{
    Composit::Leaf a;
    Composit::Composit b(a);    // b->a
    Composit::Composit c(b);    // c->b->a
    Composit::Composit d(c);    // d->c->b->a
}

如评论中所示,我希望有某种形式的递归 link。 相反,我发现“b”、“c”和“d”的“child_”引用了“a”。 当 Composit 构造函数的参数是指向组件的指针时,我可以获得预期的行为。

Composit(Component* x) :
                child_(*x)
            { }

而变量b,c,d的定义显然使用了a,b,c的地址

Composit::Leaf a;
Composit::Composit b(&a);    // b->a
Composit::Composit c(&b);    // c->b->a
Composit::Composit d(&c);    // d->c->b->a

使用引用作为参数的版本是否没有像我预期的那样工作?

谢谢。

编辑: 我试过这段代码

void f(Composit::Component& x)
{
    x.operation();
}



int main()
{
    Composit::Leaf a;
    Composit::Composit b(a);    // b->a
    Composit::Composit c(b);    // c->b->a
    Composit::Composit d(c);    // d->c->b->a

    f(d);
    f(c);
    f(b);
    f(a);

}

得到这个输出

00D7F858: I am a composit!
00D7F888: I am a leaf
00D7F868: I am a composit!
00D7F888: I am a leaf
00D7F878: I am a composit!
00D7F888: I am a leaf
00D7F888: I am a leaf

这是我传递指针时得到的结果

int main()
{
    Composit::Leaf a;
    Composit::Composit b(&a);    // b->a
    Composit::Composit c(&b);    // c->b->a
    Composit::Composit d(&c);    // d->c->b->a

    f(d);
    f(c);
    f(b);
    f(a);

}
00DEF9D4: I am a composit!
00DEF9E4: I am a composit!
00DEF9F4: I am a composit!
00DEFA04: I am a leaf
00DEF9E4: I am a composit!
00DEF9F4: I am a composit!
00DEFA04: I am a leaf
00DEF9F4: I am a composit!
00DEFA04: I am a leaf
00DEFA04: I am a leaf

因为Composit::Composit c(b)调用了默认生成的拷贝构造函数。这就是指针版本有效的原因,因为 Composit* 参数不适用于复制构造函数。

没有很好的方法来防止这种行为,因为如果 Composit::Composit c(b) 有效,大多数 containers/generic 算法将期望这是一个副本(但它不会,因为它只会使 c 成为 b 的包装器)。我会建议一个工厂函数来代替 Composit 对象。