带有引用的多态性没有按预期运行
Polymorphism with references does not behave as expected
据我所知,引用的多态性应该和指针的多态性一样工作。
然而,请考虑以下示例:当使用指针时,对doer()
的调用是正确调度的,但当使用引用时,似乎在这两种情况下都调用了"B版本"。
我不明白下面的例子为什么会这样。为什么在使用引用时,在这两种情况下都调用"B版本"?
#include <iostream>
class B;
class C;
void doer(B *x) {
std::cout << "B version" << std::endl;
}
void doer(C *x) {
std::cout << "C version" << std::endl;
}
class A {
public:
virtual ~A() {}
virtual void doit() = 0;
};
class B: public A {
public:
virtual void doit() override {
doer(this);
}
};
class C: public A {
public:
virtual void doit() override {
doer(this);
}
};
int main() {
B b;
C c;
A *a = &b;
a->doit(); // B version gets called, OK
a = &c;
a->doit(); // C version is called, OK
A &d = b;
d.doit(); // B version is called, OK
d = c;
d.doit(); // B version is called again??
}
在这里分配一个引用:
A &d = b;
d.doit(); // B version is called, OK
在这里,用c覆盖d引用的对象(它不再是引用的定义):
d = c;
d.doit(); // B version is called again??
这就是引用和指针之间的主要区别。引用就像一个常量指针,只能在定义时指定。之后,每当你使用引用时,它就意味着你引用的对象
事实上,当您执行d = c;
时,会发生一些切片。对象d实际上是一个B,但来自a的operator=
被调用,只复制a的成员数据。
以下是如何证明这一声明:
class A {
public:
...
A& operator= (A a) {
cout << "A::operator=" << endl; // just to show what happens when d=c is called
return *this;
}
};
class B : public A {
public:
int x; // add some variables for B
virtual void doit() override {
cout << "B::doit() " << x << endl;
doer(this);
}
};
class C : public A {
public:
int a,b; // add aditional variables for C
virtual void doit() override {
cout << "C::doit() " << a << ","<<b << endl;
doer(this);
}
};
...
b.x = 123; // put some class specific variables in C
c.a = 222; c.b = 333; // put some class specific variables in C
A &d = b; // assignement of the reference. d reffers to a b object
d.doit(); // B version is called, OK
d = c; // but an A object is copied (so only A subobject of c is taken
// to overwrite A subobject of d)
d.doit(); // B version is called becaus again?? => yes !! because it's still a B
// And you see that the B part of the object is left intact by A::operator=
cout << typeid(d).name() << endl;
// remember at this point that d still refers to b !
引用在其整个生命周期中都由其引用对象绑定,并且与指针不同,需要初始化。使用赋值运算符调用引用的赋值运算符,是否不重新分配引用:
A &d = b;
d = c;
这里,d = c
从d
中包含的基类A
子对象调用赋值运算符,并复制c
中包含的A
子对象数据。
相关文章:
- 为什么我们实际上需要运行时多态性?
- 运行时多态性和dynamic_cast需要澄清
- 运行时多态性 - 箭头运算符访问了错误的成员?
- C ++中的方法覆盖:是编译时还是运行时多态性?
- 运行时与编译时多态性:更好的可读性与编译时错误检查,更重要的是
- 两个不同类的运行时多态性
- 考虑 .(点)应用于应该是运行时多态性的东西时
- 如果在编译时间中创建虚拟表,那么为什么我们将其称为运行时间多态性
- 编译时多态性运行时多态性是这样的吗
- CRTP的运行时多态性设计和策略
- C++链表/多态性未运行列表函数
- 带有引用的多态性没有按预期运行
- 查询C++中的运行时多态性
- 需要使用模板解决运行时多态性的帮助
- 为什么不能在编译时解决运行时多态性?
- c++与java中运行时多态性的成本比较
- 为什么为模板实例化声明运行时多态性会导致链接器错误
- 编译时与运行时多态性在c++中的优缺点
- 允许运行时和编译时多态性的灵活方式
- c++中通过虚函数实现的运行时多态性