为什么将结构体的引用设置为另一个结构体只会改变一个数据成员?

4

当我尝试运行这段代码时, 我得到的输出是

1 1 | 1 2

不过,如果我去掉引用,也就是

// replace 
A& a_ref = b2;  
a_ref = b1;
// with 
b2 = b1;

输出结果将会改变为:

1 1 | 1 1

我找不到任何解释为什么会发生这种情况的网站。有人能够解释一下吗?

#include <iostream>
struct A {
 int foo;
};
struct B : public A {
 int bar;
 B(int x,int y) : bar(y) { this->foo=x; }
};
int main(void) {
 B b1(1,1), b2(2,2);
 A& a_ref = b2;
 a_ref = b1;
 std::cout << b1.foo << ' ' << b1.bar << " | " << b2.foo << ' ' <<
b2.bar << '\n';
 return 0;
}

3
你将 b2 对象的子对象指定为 A。由于左侧的类型是 A,因此 b1 隐式转换为 A。换句话说,该赋值相当于 a_ref = (A&)b1;。这与原语意义相符,仅作了适当的表述调整。 - Igor Tandetnik
1
进一步阅读:什么是对象切片? - cdhowie
2个回答

2
您正在使用一个 A 引用,它可以绑定到任何派生类型(指针同理)。编译器允许将其绑定到任何对象上,因此您可以忘记其确切类型是 A 还是 B,只要它从 A 继承即可。显然,它不知道任何派生类型的内部情况,因此它只做 A 的事情。
这可能需要使用虚函数来处理;在这种情况下,编译器会负责放置一个指向“真实”函数(不仅是基础类型中的函数)的指针表。由于这些函数共享其特征,调用者可以调用其中任何一个函数,而不用关心其内部发生了什么。
话虽如此,您可以定义一个虚拟复制赋值运算符,它将执行您所期望的操作......或者也许不会!
我被愚弄了,并且认为您可以,但您确实无法......请参阅C++虚拟赋值运算符以了解原因。

2
当你执行以下操作时:
A& a_ref = b2; 

参考a_ref只涉及从A继承而来的B成员。毕竟,A&无法知道派生类的成员。

因此,当你执行以下操作时:

a_ref = b1;
a_ref 只复制了它知道的成员,也就是只有 foo。所以只有 b2.foo 发生了改变。
在这种情况下:
b2 = b1;

你正在复制一个 B 对象的所有成员,因此所有成员都会被更改。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接