意外的引用行为
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
对象。
我正在研究复合模式并遇到以下代码的意外行为:
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
对象。